diff --git a/.projenrc.js b/.projenrc.js
index 185c5a23..a0bee92b 100644
--- a/.projenrc.js
+++ b/.projenrc.js
@@ -44,7 +44,12 @@ project.prettier.addIgnorePattern('API.md');
project.prettier.addIgnorePattern('package.json');
project.jest.addIgnorePattern('/lambda/');
project.gitignore.addPatterns('/assets');
-project.npmignore.addPatterns('/lambda', '/dist-lambda', '/scripts', '!/assets');
+project.npmignore.addPatterns(
+ '/lambda',
+ '/dist-lambda',
+ '/scripts',
+ '!/assets',
+);
goreleaserArtifactsNamespace = 'build-artifact-goreleaser';
diff --git a/API.md b/API.md
index 022e80f1..c15ce3a3 100644
--- a/API.md
+++ b/API.md
@@ -1197,6 +1197,7 @@ const sopsSecretProps: SopsSecretProps = { ... }
| sopsKmsKey
| aws-cdk-lib.aws_kms.IKey[]
| The kmsKey used to encrypt the sops file. |
| sopsProvider
| SopsSyncProvider
| The custom resource provider to use. |
| stringifyValues
| boolean
| Shall all values be flattened? |
+| uploadType
| UploadType
| How should the secret be passed to the CustomResource? |
---
@@ -1397,6 +1398,19 @@ are lookup errors for certain float types
---
+##### `uploadType`Optional
+
+```typescript
+public readonly uploadType: UploadType;
+```
+
+- *Type:* UploadType
+- *Default:* INLINE
+
+How should the secret be passed to the CustomResource?
+
+---
+
### SopsSyncOptions
Configuration options for the SopsSync.
@@ -1421,6 +1435,7 @@ const sopsSyncOptions: SopsSyncOptions = { ... }
| sopsKmsKey
| aws-cdk-lib.aws_kms.IKey[]
| The kmsKey used to encrypt the sops file. |
| sopsProvider
| SopsSyncProvider
| The custom resource provider to use. |
| stringifyValues
| boolean
| Shall all values be flattened? |
+| uploadType
| UploadType
| How should the secret be passed to the CustomResource? |
---
@@ -1540,6 +1555,19 @@ are lookup errors for certain float types
---
+##### `uploadType`Optional
+
+```typescript
+public readonly uploadType: UploadType;
+```
+
+- *Type:* UploadType
+- *Default:* INLINE
+
+How should the secret be passed to the CustomResource?
+
+---
+
### SopsSyncProps
The configuration options extended by the target Secret.
@@ -1564,6 +1592,7 @@ const sopsSyncProps: SopsSyncProps = { ... }
| sopsKmsKey
| aws-cdk-lib.aws_kms.IKey[]
| The kmsKey used to encrypt the sops file. |
| sopsProvider
| SopsSyncProvider
| The custom resource provider to use. |
| stringifyValues
| boolean
| Shall all values be flattened? |
+| uploadType
| UploadType
| How should the secret be passed to the CustomResource? |
| secret
| aws-cdk-lib.aws_secretsmanager.ISecret
| The secret that will be populated with the encrypted sops file content. |
---
@@ -1684,6 +1713,19 @@ are lookup errors for certain float types
---
+##### `uploadType`Optional
+
+```typescript
+public readonly uploadType: UploadType;
+```
+
+- *Type:* UploadType
+- *Default:* INLINE
+
+How should the secret be passed to the CustomResource?
+
+---
+
##### `secret`Required
```typescript
@@ -1698,3 +1740,29 @@ The secret that will be populated with the encrypted sops file content.
+## Enums
+
+### UploadType
+
+#### Members
+
+| **Name** | **Description** |
+| --- | --- |
+| INLINE
| Pass the secret data inline (base64 encoded and compressed). |
+| ASSET
| Uplaod the secert data as asset. |
+
+---
+
+##### `INLINE`
+
+Pass the secret data inline (base64 encoded and compressed).
+
+---
+
+
+##### `ASSET`
+
+Uplaod the secert data as asset.
+
+---
+
diff --git a/README.md b/README.md
index 7addada5..16cacf0e 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,23 @@ Sometimes it can be necessary to access the IAM role of the SopsSync provider. I
});
```
+### UploadType: INLINE / ASSET — What when why?
+
+I decided, that the default behavior should be "INLINE" because of the following consideration:
+
+* Fewer permissions: If we use inline content instead of a S3 asset, the SopsSyncProvider does not need permissions to access the asset bucket and its KMS key.
+* Faster: If we don't have to upload and download things from and to S3, it should be a little faster.
+* Interchangeable: As we use the same information to generate the version of the secret, no new version of the secret should be created, if you change from INLINE to ASSET or vice versa, even if the CloudFormation resource updates.
+* I personally think sops files are not that big, that we should run into limits, but if so — we can change to asset ```uploadType```.
+
+You can change the uplaodType via the properties:
+
+```typescript
+const secret = new SopsSecret(this, 'SopsWithAssetUpload', {
+ sopsFilePath: 'secrets/sopsfile-encrypted.json',
+ uploadType: UploadType.ASSET // instead of the default UploadType.INLINE
+});
+```
## Motivation
I have created this project to solve a recurring problem of syncing Mozilla/sops secrets into AWS SecretsManager in a convenient, secure way.
diff --git a/src/index.ts b/src/index.ts
index 04bd42df..93111e57 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -62,7 +62,7 @@ export interface SopsSyncOptions {
* How should the secret be passed to the CustomResource?
* @default INLINE
*/
- readonly uploadType?: UploadType
+ readonly uploadType?: UploadType;
/**
* The format of the sops file.
@@ -180,29 +180,27 @@ export class SopsSync extends Construct {
throw new Error(`File ${props.sopsFilePath} does not exist!`);
}
-
-
/**
* Handle uploadType INLINE or ASSET
*/
const uploadType = props.uploadType ?? UploadType.INLINE;
- let sopsAsset:Asset|undefined = undefined;
- let sopsInline:{Content:string, Hash:string}|undefined = undefined;
- let sopsS3File:{Bucket:string, Key:string}|undefined = undefined;
- if ( uploadType === UploadType.INLINE ) {
+ let sopsAsset: Asset | undefined = undefined;
+ let sopsInline: { Content: string; Hash: string } | undefined = undefined;
+ let sopsS3File: { Bucket: string; Key: string } | undefined = undefined;
+ if (uploadType === UploadType.INLINE) {
sopsInline = {
Content: fs.readFileSync(props.sopsFilePath).toString('base64'),
// We calculate the hash the same way as it would be done by new Asset(..) - so we can ensure stable version names even if switching from INLINE to ASSET and viceversa.
Hash: FileSystem.fingerprint(props.sopsFilePath),
- }
- } else if ( uploadType === UploadType.ASSET ) {
+ };
+ } else if (uploadType === UploadType.ASSET) {
sopsAsset = new Asset(this, 'Asset', {
path: props.sopsFilePath,
});
- sopsS3File = {
+ sopsS3File = {
Bucket: sopsAsset.bucket.bucketName,
Key: sopsAsset.s3ObjectKey,
- }
+ };
} else {
throw new Error(`Unsupported UploadType: ${uploadType}`);
}
@@ -222,12 +220,16 @@ export class SopsSync extends Construct {
);
}
props.secret.grantWrite(provider);
- if ( sopsAsset !== undefined ) {
+ if (sopsAsset !== undefined) {
sopsAsset.bucket.grantRead(provider);
}
} else {
Annotations.of(this).addWarning(
- `Please ensure propper permissions for the passed lambda function:\n - write Access to the secret\n - encrypt with the sopsKmsKey${uploadType === UploadType.ASSET ? '\n - download from asset bucket' : ''}`,
+ `Please ensure propper permissions for the passed lambda function:\n - write Access to the secret\n - encrypt with the sopsKmsKey${
+ uploadType === UploadType.ASSET
+ ? '\n - download from asset bucket'
+ : ''
+ }`,
);
}
if (props.sopsAgeKey !== undefined) {
@@ -240,7 +242,7 @@ export class SopsSync extends Construct {
properties: {
SecretARN: props.secret.secretArn,
SopsS3File: sopsS3File,
- SopsInline: sopsInline,
+ SopsInline: sopsInline,
ConvertToJSON: this.converToJSON,
Flatten: this.flatten,
Format: this.sopsFileFormat,