Skip to content

Commit

Permalink
feat: save certificate and private key file to a S3 bucket (#6)
Browse files Browse the repository at this point in the history
* refactor

* test: integ test

* update file path

* update api.md

* chore: self mutation

Signed-off-by: github-actions <[email protected]>

---------

Signed-off-by: github-actions <[email protected]>
Co-authored-by: github-actions <[email protected]>
  • Loading branch information
badmintoncryer and github-actions authored Oct 28, 2024
1 parent 61be083 commit b0828b3
Show file tree
Hide file tree
Showing 17 changed files with 3,447 additions and 1,041 deletions.
14 changes: 14 additions & 0 deletions API.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@ npm i cdk-iot-core-certificates-v3
## Usage

```typescript
import * as s3 from 'aws-cdk-lib/aws-s3';
import { ThingWithCert } from 'cdk-iot-core-certificates-v3';

declare const saveFileBucket: s3.IBucket;

const { thingArn, certId, certPem, privKey } = new ThingWithCert(this, 'MyThing', {
// The name of the thing
thingName: 'MyThing',
// Whether to save the certificate and private key to the SSM Parameter Store
saveToParamStore: true,
// The prefix to use for the SSM Parameter Store parameters
paramPrefix: 'test',
// The bucket to save the certificate and private key to
// Both files are saved at `{thingName}/{thingName}.private.key` and `{thingName}/{thingName}.cert.pem`
// If not provided, the certificate and private key will not be saved
saveFileBucket,
});
```
53 changes: 37 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { join } from 'node:path';
import { Duration, ResourceProps } from 'aws-cdk-lib';
import { CfnCustomResource } from 'aws-cdk-lib/aws-cloudformation';
import { CompositePrincipal, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
import { CfnParameter } from 'aws-cdk-lib/aws-ssm';
import * as cfn from 'aws-cdk-lib/aws-cloudformation';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
import * as logs from 'aws-cdk-lib/aws-logs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
import * as ssm from 'aws-cdk-lib/aws-ssm';
import { Provider } from 'aws-cdk-lib/custom-resources';
import { Construct } from 'constructs';

Expand All @@ -26,6 +29,13 @@ export interface ThingWithCertProps extends ResourceProps {
* The prefix for the parameter store path
*/
readonly paramPrefix?: string;

/**
* The bucket to save the certificate and private key files
*
* @default - do not save the files
*/
readonly saveFileBucket?: s3.IBucket;
}

/**
Expand Down Expand Up @@ -56,39 +66,40 @@ export class ThingWithCert extends Construct {
constructor(scope: Construct, id: string, props: ThingWithCertProps) {
super(scope, id);

const { thingName, saveToParamStore, paramPrefix } = props;
const { thingName, saveToParamStore, paramPrefix, saveFileBucket } = props;

const role = new Role(this, 'LambdaExecutionRole', {
assumedBy: new CompositePrincipal(new ServicePrincipal('lambda.amazonaws.com')),
const role = new iam.Role(this, 'LambdaExecutionRole', {
assumedBy: new iam.CompositePrincipal(new iam.ServicePrincipal('lambda.amazonaws.com')),
});

role.addToPolicy(
new PolicyStatement({
new iam.PolicyStatement({
resources: ['arn:aws:logs:*:*:*'],
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
}),
);

role.addToPolicy(
new PolicyStatement({
new iam.PolicyStatement({
resources: ['*'],
actions: ['iot:*'],
}),
);

const onEventHandler = new NodejsFunction(this, 'lambdaFunction', {
entry: join(__dirname, 'lambda', 'index.js'),
const onEventHandler = new nodejs.NodejsFunction(this, 'lambdaFunction', {
entry: join(__dirname, 'lambda', 'index.ts'),
handler: 'handler',
timeout: Duration.seconds(10),
role,
logRetention: RetentionDays.ONE_DAY,
runtime: lambda.Runtime.NODEJS_LATEST,
logRetention: logs.RetentionDays.ONE_DAY,
});

const { serviceToken } = new Provider(this, 'lambdaProvider', {
onEventHandler,
});

const lambdaCustomResource = new CfnCustomResource(this, 'lambdaCustomResource', {
const lambdaCustomResource = new cfn.CfnCustomResource(this, 'lambdaCustomResource', {
serviceToken,
});

Expand All @@ -97,13 +108,13 @@ export class ThingWithCert extends Construct {
const paramStorePath = getParamStorePath(thingName, paramPrefix);

if (saveToParamStore) {
new CfnParameter(this, 'paramStoreCertPem', {
new ssm.CfnParameter(this, 'paramStoreCertPem', {
type: 'String',
value: lambdaCustomResource.getAtt('certPem').toString(),
name: `${paramStorePath}/certPem`,
});

new CfnParameter(this, 'paramStorePrivKey', {
new ssm.CfnParameter(this, 'paramStorePrivKey', {
type: 'String',
value: lambdaCustomResource.getAtt('privKey').toString(),
name: `${paramStorePath}/privKey`,
Expand All @@ -114,6 +125,16 @@ export class ThingWithCert extends Construct {
this.certId = lambdaCustomResource.getAtt('certId').toString();
this.certPem = lambdaCustomResource.getAtt('certPem').toString();
this.privKey = lambdaCustomResource.getAtt('privKey').toString();

if (saveFileBucket) {
new s3deploy.BucketDeployment(this, 'SaveFile', {
sources: [
s3deploy.Source.data(`${thingName}/${thingName}.cert.pem`, this.certPem),
s3deploy.Source.data(`${thingName}/${thingName}.private.key`, this.privKey),
],
destinationBucket: saveFileBucket,
});
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
{
"version": "34.0.0",
"files": {
"21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": {
"f3de7fa69bbae9bbe9472b98f9b1b3626a9ee748b2fd5895278331be04efa56b": {
"source": {
"path": "asset.f3de7fa69bbae9bbe9472b98f9b1b3626a9ee748b2fd5895278331be04efa56b.bundle",
"packaging": "zip"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "f3de7fa69bbae9bbe9472b98f9b1b3626a9ee748b2fd5895278331be04efa56b.zip",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
},
"2f754a10da99e89275339606fae6434d70bbbff534d8faa60b2afc07eb2ee121": {
"source": {
"path": "IntegTestDefaultTestDeployAssertE3E7D2A4.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
"objectKey": "2f754a10da99e89275339606fae6434d70bbbff534d8faa60b2afc07eb2ee121.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Loading

0 comments on commit b0828b3

Please sign in to comment.