From d363e6752de771a52abed7d09404b755c97b0ef2 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Sun, 7 Feb 2021 23:02:33 -0500 Subject: [PATCH 1/6] Permit populating kms creds from config --- .../KmsConverterPluginIntegrationTest.java | 4 ++++ .../me/frmr/rundeck/KmsConverterPlugin.java | 24 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/src/integrationTest/java/me/frmr/rundeck/KmsConverterPluginIntegrationTest.java b/lib/src/integrationTest/java/me/frmr/rundeck/KmsConverterPluginIntegrationTest.java index 2533663..9985c0d 100644 --- a/lib/src/integrationTest/java/me/frmr/rundeck/KmsConverterPluginIntegrationTest.java +++ b/lib/src/integrationTest/java/me/frmr/rundeck/KmsConverterPluginIntegrationTest.java @@ -23,6 +23,8 @@ void testIgnoresNonKmsData() throws IOException { var exampleMessage = "Hello, KMS!"; var sut = new KmsConverterPlugin(); sut.keyArn = System.getenv("KMS_KEY_ARN"); + sut.accessKeyId = System.getenv("AWS_ACCESS_KEY_ID"); + sut.secretAccessKey = System.getenv("AWS_SECRET_ACCESS_KEY"); if (sut.keyArn == null) { throw new RuntimeException("Env var KMS_KEY_ARN required for integration tests"); @@ -63,6 +65,8 @@ void testEncryptDecrypt() throws IOException { var exampleMessage = "Hello, KMS!"; var sut = new KmsConverterPlugin(); sut.keyArn = System.getenv("KMS_KEY_ARN"); + sut.accessKeyId = System.getenv("AWS_ACCESS_KEY_ID"); + sut.secretAccessKey = System.getenv("AWS_SECRET_ACCESS_KEY"); if (sut.keyArn == null) { throw new RuntimeException("Env var KMS_KEY_ARN required for integration tests"); diff --git a/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java b/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java index c9397a4..9e1b6c1 100644 --- a/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java +++ b/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java @@ -7,6 +7,8 @@ import com.dtolabs.rundeck.plugins.storage.StorageConverterPlugin; import org.rundeck.storage.api.HasInputStream; import org.rundeck.storage.api.Path; + +import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.encryptionsdk.*; import com.amazonaws.encryptionsdk.kms.*; import java.util.Collections; @@ -33,6 +35,18 @@ static void addMetadataWasEncrypted(ResourceMetaBuilder resourceMetaBuilder) { @PluginProperty(title="Key ARN", description="The ARN of the KMS key to use for encryption and decryption", required=true) String keyArn; + /** + * Configuration provided Access Key Id + */ + @PluginProperty(title="Access Key ID", description = "The access key that should be used when accessing KMS", required=false) + String accessKeyId; + + /** + * Configuration provied secret access key + */ + @PluginProperty(title="Secret Access Key", description = "The secret access key that should be used when accessing KMS", required = false) + String secretAccessKey; + /** read the stored data, decrypt if necessary */ public HasInputStream readResource( Path path, @@ -43,7 +57,10 @@ public HasInputStream readResource( return null; } - KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider.builder().buildStrict(keyArn); + KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider + .builder() + .withCredentials(new BasicAWSCredentials(accessKeyId, secretAccessKey)) + .buildStrict(keyArn); CryptoMaterialsManager materialsManager = new DefaultCryptoMaterialsManager(keyProvider); return new DecryptionStream(hasInputStream, materialsManager); } @@ -54,7 +71,10 @@ public HasInputStream createResource( ResourceMetaBuilder resourceMetaBuilder, HasInputStream hasInputStream){ - KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider.builder().buildStrict(keyArn); + KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider + .builder() + .withCredentials(new BasicAWSCredentials(accessKeyId, secretAccessKey)) + .buildStrict(keyArn); Map encryptionContext = Collections.singletonMap("path", path.getPath()); CryptoMaterialsManager materialsManager = new DefaultCryptoMaterialsManager(keyProvider); addMetadataWasEncrypted(resourceMetaBuilder); From 47e36efd64f7d508789301ec8f6cf3360bb50ce6 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Sun, 7 Feb 2021 23:06:06 -0500 Subject: [PATCH 2/6] Update readme for new authentication method --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8f91f17..ce3ad0e 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,17 @@ If I get interest in a version of the JAR that uses a _shared_ AWS SDK, I'm happ That would work better for folks who already package the AWS SDK in Rundeck's classpath in its entirety. -## Authentication +## Configuration -If you're running Rundeck within AWS, you canuse instance roles to assign the -proper permissions for Rundeck to access KMS for the use of this plugin. +The following in your `rundeck-config.properties` will configure this plugin: -I still need to add code to handle passing these values in from configuration. - -For testing purposes, you can also set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY -as with any other AWS library, though there are likely reasons this ins't good -in production. +``` +rundeck.storage.converter.1.type=rundeck-kms-plugin +rundeck.storage.converter.1.path=keys +rundeck.storage.converter.1.config.keyArn= +rundeck.storage.converter.1.config.accessKeyId= +rundeck.storage.converter.1.config.secretAccessKey= +``` # About the Author From 0bd49485b1839eaf6c353630e318569c361879ac Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Sun, 7 Feb 2021 23:06:33 -0500 Subject: [PATCH 3/6] Make keys required --- lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java b/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java index 9e1b6c1..7738ad2 100644 --- a/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java +++ b/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java @@ -38,13 +38,13 @@ static void addMetadataWasEncrypted(ResourceMetaBuilder resourceMetaBuilder) { /** * Configuration provided Access Key Id */ - @PluginProperty(title="Access Key ID", description = "The access key that should be used when accessing KMS", required=false) + @PluginProperty(title="Access Key ID", description = "The access key that should be used when accessing KMS", required=true) String accessKeyId; /** * Configuration provied secret access key */ - @PluginProperty(title="Secret Access Key", description = "The secret access key that should be used when accessing KMS", required = false) + @PluginProperty(title="Secret Access Key", description = "The secret access key that should be used when accessing KMS", required = true) String secretAccessKey; /** read the stored data, decrypt if necessary */ From fc2276ddf2aa1c8b7c6d2c44498b2d97ba1bc2c5 Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Sun, 7 Feb 2021 23:09:15 -0500 Subject: [PATCH 4/6] Update our replacement remco configuration --- README.md | 6 ++++++ test-image/rundeck-config-storage.properties | 12 ++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ce3ad0e..be4a74d 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,12 @@ rundeck.storage.converter.1.path=keys rundeck.storage.converter.1.config.keyArn= rundeck.storage.converter.1.config.accessKeyId= rundeck.storage.converter.1.config.secretAccessKey= + +rundeck.config.storage.converter.1.type=rundeck-kms-plugin +rundeck.config.storage.converter.1.path=projects +rundeck.config.storage.converter.1.config.keyArn= +rundeck.config.storage.converter.1.config.accessKeyId= +rundeck.config.storage.converter.1.config.secretAccessKey= ``` # About the Author diff --git a/test-image/rundeck-config-storage.properties b/test-image/rundeck-config-storage.properties index a68eb0f..6b4b371 100644 --- a/test-image/rundeck-config-storage.properties +++ b/test-image/rundeck-config-storage.properties @@ -16,22 +16,18 @@ rundeck.storage.provider.{{index}}.path={% set path = printf("%s/path", provider {%- set index = converter | base %} rundeck.storage.converter.{{index}}.type={% set type = printf("%s/type", converter) %}{{ getv(type, "jasypt-encryption") }} rundeck.storage.converter.{{index}}.path={% set path = printf("%s/path", converter) %}{{ getv(path, "keys") }} -rundeck.storage.converter.{{index}}.config.encryptorType={% set encryptortype = printf("%s/config/encryptortype", converter) %}{{ getv(encryptortype, "custom") }} -rundeck.storage.converter.{{index}}.config.password={% set password = printf("%s/config/password", converter) %}{{ getv(password, "") }} -rundeck.storage.converter.{{index}}.config.algorithm={% set algorithm = printf("%s/config/algorithm", converter) %}{{ getv(algorithm, "PBEWITHSHA256AND128BITAES-CBC-BC") }} -rundeck.storage.converter.{{index}}.config.provider={% set provider = printf("%s/config/provider", converter) %}{{ getv(provider, "BC") }} rundeck.storage.converter.{{index}}.config.keyArn={% set keyArn = printf("%s/config/keyarn", converter) %}{{ getv(keyArn, "") }} +rundeck.storage.converter.{{index}}.config.awsAccessKeyId={% set awsAccessKeyId = printf("%s/config/awsaccesskeyid", converter) %}{{ getv(awsAccessKeyId, "") }} +rundeck.storage.converter.{{index}}.config.awsSecretAccessKey={% set awsSecretAccessKey = printf("%s/config/awssecretaccesskey", converter) %}{{ getv(awsSecretAccessKey, "") }} {% endmacro %} {%- macro config_storage_converter(converter) %} {%- set index = converter | base %} rundeck.config.storage.converter.{{index}}.type={% set type = printf("%s/type", converter) %}{{ getv(type, "jasypt-encryption") }} rundeck.config.storage.converter.{{index}}.path={% set path = printf("%s/path", converter) %}{{ getv(path, "projects") }} -rundeck.config.storage.converter.{{index}}.config.encryptorType={% set encryptortype = printf("%s/config/encryptortype", converter) %}{{ getv(encryptortype, "custom") }} -rundeck.config.storage.converter.{{index}}.config.password={% set password = printf("%s/config/password", converter) %}{{ getv(password, "") }} -rundeck.config.storage.converter.{{index}}.config.algorithm={% set algorithm = printf("%s/config/algorithm", converter) %}{{ getv(algorithm, "PBEWITHSHA256AND128BITAES-CBC-BC") }} -rundeck.config.storage.converter.{{index}}.config.provider={% set provider = printf("%s/config/provider", converter) %}{{ getv(provider, "BC") }} rundeck.config.storage.converter.{{index}}.config.keyArn={% set keyArn = printf("%s/config/keyarn", converter) %}{{ getv(keyArn, "") }} +rundeck.config.storage.converter.{{index}}.config.awsAccessKeyId={% set awsAccessKeyId = printf("%s/config/awsaccesskeyid", converter) %}{{ getv(awsAccessKeyId, "") }} +rundeck.config.storage.converter.{{index}}.config.awsSecretAccessKey={% set awsSecretAccessKey = printf("%s/config/awssecretaccesskey", converter) %}{{ getv(awsSecretAccessKey, "") }} {% endmacro %} {%- if ls(printf("%s/1", providerBase)) | length == 0 %} From 037e721f2c80d57530180059fd70a9bc376ebf4d Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Mon, 8 Feb 2021 12:39:07 -0500 Subject: [PATCH 5/6] Set up for testing --- .../main/java/me/frmr/rundeck/KmsConverterPlugin.java | 11 +++++++++-- test-in-rundeck.sh | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java b/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java index 7738ad2..6282df0 100644 --- a/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java +++ b/lib/src/main/java/me/frmr/rundeck/KmsConverterPlugin.java @@ -8,9 +8,12 @@ import org.rundeck.storage.api.HasInputStream; import org.rundeck.storage.api.Path; +import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.encryptionsdk.*; import com.amazonaws.encryptionsdk.kms.*; +import com.amazonaws.internal.StaticCredentialsProvider; + import java.util.Collections; import java.util.Map; import java.io.*; @@ -59,7 +62,9 @@ public HasInputStream readResource( KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider .builder() - .withCredentials(new BasicAWSCredentials(accessKeyId, secretAccessKey)) + .withCredentials(new AWSStaticCredentialsProvider( + new BasicAWSCredentials(accessKeyId, secretAccessKey) + )) .buildStrict(keyArn); CryptoMaterialsManager materialsManager = new DefaultCryptoMaterialsManager(keyProvider); return new DecryptionStream(hasInputStream, materialsManager); @@ -73,7 +78,9 @@ public HasInputStream createResource( KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider .builder() - .withCredentials(new BasicAWSCredentials(accessKeyId, secretAccessKey)) + .withCredentials(new AWSStaticCredentialsProvider( + new BasicAWSCredentials(accessKeyId, secretAccessKey) + )) .buildStrict(keyArn); Map encryptionContext = Collections.singletonMap("path", path.getPath()); CryptoMaterialsManager materialsManager = new DefaultCryptoMaterialsManager(keyProvider); diff --git a/test-in-rundeck.sh b/test-in-rundeck.sh index d2ed499..ae7cd40 100755 --- a/test-in-rundeck.sh +++ b/test-in-rundeck.sh @@ -5,12 +5,12 @@ set -e docker build -t rundeck-kms-test-image test-image docker run -it \ - -e AWS_ACCESS_KEY_ID \ - -e AWS_SECRET_ACCESS_KEY \ -e AWS_REGION \ -e RUNDECK_STORAGE_CONVERTER_1_TYPE=rundeck-kms-plugin \ -e RUNDECK_STORAGE_CONVERTER_1_PATH=keys \ -e RUNDECK_STORAGE_CONVERTER_1_CONFIG_KEYARN=$KMS_KEY_ARN \ + -e RUNDECK_STORAGE_CONVERTER_1_CONFIG_AWSACCESSKEYID=$AWS_ACCESS_KEY_ID \ + -e RUNDECK_STORAGE_CONVERTER_1_CONFIG_AWSSECRETACCESSKEY=$AWS_SECRET_ACCESS_KEY \ -p 4440:4440 \ -v $(pwd)/lib/build/libs/rundeck-kms-plugin.jar:/home/rundeck/libext/rundeck-kms-plugin.jar \ rundeck-kms-test-image From 4ea2834c5c723589d985b5b982ab9ffcf83653ca Mon Sep 17 00:00:00 2001 From: Matt Farmer Date: Mon, 8 Feb 2021 12:42:38 -0500 Subject: [PATCH 6/6] Correct config template --- test-image/rundeck-config-storage.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-image/rundeck-config-storage.properties b/test-image/rundeck-config-storage.properties index 6b4b371..95f1913 100644 --- a/test-image/rundeck-config-storage.properties +++ b/test-image/rundeck-config-storage.properties @@ -17,8 +17,8 @@ rundeck.storage.provider.{{index}}.path={% set path = printf("%s/path", provider rundeck.storage.converter.{{index}}.type={% set type = printf("%s/type", converter) %}{{ getv(type, "jasypt-encryption") }} rundeck.storage.converter.{{index}}.path={% set path = printf("%s/path", converter) %}{{ getv(path, "keys") }} rundeck.storage.converter.{{index}}.config.keyArn={% set keyArn = printf("%s/config/keyarn", converter) %}{{ getv(keyArn, "") }} -rundeck.storage.converter.{{index}}.config.awsAccessKeyId={% set awsAccessKeyId = printf("%s/config/awsaccesskeyid", converter) %}{{ getv(awsAccessKeyId, "") }} -rundeck.storage.converter.{{index}}.config.awsSecretAccessKey={% set awsSecretAccessKey = printf("%s/config/awssecretaccesskey", converter) %}{{ getv(awsSecretAccessKey, "") }} +rundeck.storage.converter.{{index}}.config.accessKeyId={% set awsAccessKeyId = printf("%s/config/awsaccesskeyid", converter) %}{{ getv(awsAccessKeyId, "") }} +rundeck.storage.converter.{{index}}.config.secretAccessKey={% set awsSecretAccessKey = printf("%s/config/awssecretaccesskey", converter) %}{{ getv(awsSecretAccessKey, "") }} {% endmacro %} {%- macro config_storage_converter(converter) %} @@ -26,8 +26,8 @@ rundeck.storage.converter.{{index}}.config.awsSecretAccessKey={% set awsSecretAc rundeck.config.storage.converter.{{index}}.type={% set type = printf("%s/type", converter) %}{{ getv(type, "jasypt-encryption") }} rundeck.config.storage.converter.{{index}}.path={% set path = printf("%s/path", converter) %}{{ getv(path, "projects") }} rundeck.config.storage.converter.{{index}}.config.keyArn={% set keyArn = printf("%s/config/keyarn", converter) %}{{ getv(keyArn, "") }} -rundeck.config.storage.converter.{{index}}.config.awsAccessKeyId={% set awsAccessKeyId = printf("%s/config/awsaccesskeyid", converter) %}{{ getv(awsAccessKeyId, "") }} -rundeck.config.storage.converter.{{index}}.config.awsSecretAccessKey={% set awsSecretAccessKey = printf("%s/config/awssecretaccesskey", converter) %}{{ getv(awsSecretAccessKey, "") }} +rundeck.config.storage.converter.{{index}}.config.accessKeyId={% set awsAccessKeyId = printf("%s/config/awsaccesskeyid", converter) %}{{ getv(awsAccessKeyId, "") }} +rundeck.config.storage.converter.{{index}}.config.secretAccessKey={% set awsSecretAccessKey = printf("%s/config/awssecretaccesskey", converter) %}{{ getv(awsSecretAccessKey, "") }} {% endmacro %} {%- if ls(printf("%s/1", providerBase)) | length == 0 %}