From c45dde0407e4407907d26d4e3bf26c752d2fc5c6 Mon Sep 17 00:00:00 2001
From: Martin Altmayer <141163644+MartinAltmayerTMH@users.noreply.github.com>
Date: Wed, 4 Dec 2024 17:45:55 +0100
Subject: [PATCH] feat: Support placing the lambda into a VPC (#1078)
* feat: Support placing the lambda into a VPC
* docs: Add documentation for SopsSyncProviderProps
* docs: Add example for lambda networking configuration
---
API.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-
README.md | 24 ++++++++++++++++-
src/SopsSync.ts | 30 ++++++++++++++++++++-
3 files changed, 121 insertions(+), 3 deletions(-)
diff --git a/API.md b/API.md
index b222fe53..4658531e 100644
--- a/API.md
+++ b/API.md
@@ -962,13 +962,14 @@ The current versionId of the secret populated via this resource.
```typescript
import { SopsSyncProvider } from 'cdk-sops-secrets'
-new SopsSyncProvider(scope: Construct, id?: string)
+new SopsSyncProvider(scope: Construct, id?: string, props?: SopsSyncProviderProps)
```
| **Name** | **Type** | **Description** |
| --- | --- | --- |
| scope
| constructs.Construct
| *No description.* |
| id
| string
| *No description.* |
+| props
| SopsSyncProviderProps
| *No description.* |
---
@@ -984,6 +985,12 @@ new SopsSyncProvider(scope: Construct, id?: string)
---
+##### `props`Optional
+
+- *Type:* SopsSyncProviderProps
+
+---
+
#### Methods
| **Name** | **Description** |
@@ -3388,6 +3395,67 @@ The secret that will be populated with the encrypted sops file content.
---
+### SopsSyncProviderProps
+
+Configuration options for a custom SopsSyncProvider.
+
+#### Initializer
+
+```typescript
+import { SopsSyncProviderProps } from 'cdk-sops-secrets'
+
+const sopsSyncProviderProps: SopsSyncProviderProps = { ... }
+```
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| securityGroups
| aws-cdk-lib.aws_ec2.ISecurityGroup[]
| Only if `vpc` is supplied: The list of security groups to associate with the Lambda's network interfaces. |
+| vpc
| aws-cdk-lib.aws_ec2.IVpc
| VPC network to place Lambda network interfaces. |
+| vpcSubnets
| aws-cdk-lib.aws_ec2.SubnetSelection
| Where to place the network interfaces within the VPC. |
+
+---
+
+##### `securityGroups`Optional
+
+```typescript
+public readonly securityGroups: ISecurityGroup[];
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[]
+- *Default:* A dedicated security group will be created for the lambda function.
+
+Only if `vpc` is supplied: The list of security groups to associate with the Lambda's network interfaces.
+
+---
+
+##### `vpc`Optional
+
+```typescript
+public readonly vpc: IVpc;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.IVpc
+- *Default:* Lambda function is not placed within a VPC.
+
+VPC network to place Lambda network interfaces.
+
+---
+
+##### `vpcSubnets`Optional
+
+```typescript
+public readonly vpcSubnets: SubnetSelection;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.SubnetSelection
+- *Default:* Subnets will be chosen automatically.
+
+Where to place the network interfaces within the VPC.
+
+---
+
## Enums
diff --git a/README.md b/README.md
index cff7c966..2ec0fd8d 100644
--- a/README.md
+++ b/README.md
@@ -127,6 +127,28 @@ const secret = new SopsSecret(this, 'SopsComplexSecretJSON', {
});
```
+
+### Use a VPC for the Lambda Function
+
+Internally, SopsSync uses a lambda function. In some environments it may be necessary to place this lambda function into a VPC and configure subnets and/or security groups for it.
+This can be done by creating a custom `SopsSyncProvider`, setting the required networking configuration and passing it to the secret like this:
+
+```typescript
+// Create the provider
+const provider = new SopsSyncProvider(this, 'CustomSopsSyncProvider', {
+ vpc: myVpc,
+ vpcSubnets: subnetSelection,
+ securityGroups: [mySecurityGroup],
+});
+// create the secret and pass the the provider to it
+const secret = new SopsSecret(this, 'SopsSecret', {
+ sopsProvider: provider,
+ secretName: 'myCoolSecret',
+ sopsFilePath: 'secrets/sopsfile-encrypted.json',
+});
+```
+
+
### UploadType: INLINE / ASSET
I decided, that the default behavior should be "INLINE" because of the following consideration:
@@ -247,4 +269,4 @@ The problem this Construct addresses is so good, already two other implementatio
## License
-The Apache-2.0 license. Please have a look at the [LICENSE](LICENSE) and [LICENSE-3RD-PARTY](LICENSE-3RD-PARTY).
\ No newline at end of file
+The Apache-2.0 license. Please have a look at the [LICENSE](LICENSE) and [LICENSE-3RD-PARTY](LICENSE-3RD-PARTY).
diff --git a/src/SopsSync.ts b/src/SopsSync.ts
index 89c63aed..244d0976 100644
--- a/src/SopsSync.ts
+++ b/src/SopsSync.ts
@@ -9,6 +9,7 @@ import {
CustomResource,
FileSystem,
} from 'aws-cdk-lib';
+import { ISecurityGroup, IVpc, SubnetSelection } from 'aws-cdk-lib/aws-ec2';
import {
IGrantable,
IRole,
@@ -169,10 +170,34 @@ export interface SopsSyncProps extends SopsSyncOptions {
readonly encryptionKey?: IKey;
}
+/**
+ * Configuration options for a custom SopsSyncProvider.
+ */
+export interface SopsSyncProviderProps {
+ /**
+ * VPC network to place Lambda network interfaces.
+ *
+ * @default - Lambda function is not placed within a VPC.
+ */
+ readonly vpc?: IVpc;
+ /**
+ * Where to place the network interfaces within the VPC.
+ *
+ * @default - Subnets will be chosen automatically.
+ */
+ readonly vpcSubnets?: SubnetSelection;
+ /**
+ * Only if `vpc` is supplied: The list of security groups to associate with the Lambda's network interfaces.
+ *
+ * @default - A dedicated security group will be created for the lambda function.
+ */
+ readonly securityGroups?: ISecurityGroup[];
+}
+
export class SopsSyncProvider extends SingletonFunction implements IGrantable {
private sopsAgeKeys: SecretValue[];
- constructor(scope: Construct, id?: string) {
+ constructor(scope: Construct, id?: string, props?: SopsSyncProviderProps) {
super(scope, id ?? 'SopsSyncProvider', {
code: Code.fromAsset(
scope.node.tryGetContext('sops_sync_provider_asset_path') ||
@@ -190,6 +215,9 @@ export class SopsSyncProvider extends SingletonFunction implements IGrantable {
),
}),
},
+ vpc: props?.vpc,
+ vpcSubnets: props?.vpcSubnets,
+ securityGroups: props?.securityGroups,
});
this.sopsAgeKeys = [];
}