How to retrieve SecretsManager secret in AWS CDK - amazon-web-services

I'm setting up a Fargate service in AWS using CDK
const albFargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(
this,
'FargateService',
{
vpc: ...,
taskImageOptions: {
image: ...,
containerPort: ...,
secrets: {
MY_ENV_VAR: Secret.fromSecretsManager(
**ISecret**,
'fieldWithinTheSecret'
),
}
}
}
)
How am I supposed to get hold of the ISecret instance given the name of the secret?
I've looked at the AWS.SecretsManager from the AWS SDK, but it only returns strings.

Currently there is no Secret.fromSecretName-method. Assuming that you are using an existing secret, you should use the Secret.fromSecretArn-method.
Note that if you use a KMS key, you should use the Secret.fromSecretAttributes-method as described at Get a value from AWS secrets manager.
import * as ecs from "#aws-cdk/aws-ecs";
import * as ecs_patterns from "#aws-cdk/aws-ecs-patterns";
import * as secretsmanager from "#aws-cdk/aws-secretsmanager";
const mySecret = secretsmanager.Secret.fromSecretArn(this, "mySecret", "arn:aws:secretsmanager:<region>:<account-id-number>:secret:<secret-name>-<random-6-characters>");
const albFargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(
this,
'FargateService',
{
vpc: ...,
taskImageOptions: {
image: ...,
containerPort: ...,
secrets: {
MY_ENV_VAR: ecs.Secret.fromSecretsManager(mySecret),
}
}
}
);

The updated one with CDK version 2
You can refer to a secret either with Secret.fromSecretNameV2() and retrieve a particular secret value using Secret.secretValueFromJson('keyname').toString();
Refer to the code snippet below
const appSecret = Secret.fromSecretNameV2(this,'app-secret',"secret-name");
const value1 = appSecret.secretValueFromJson('KeyName1').toString();
const value2 = appSecret.secretValueFromJson('KeyName2').toString();
The best thing is, you can use this secret value anywhere like Cognito
Secrets, and it will not hardcode the secret value in your cloud
formation stack. Instead, it will use a token and it will be resolved
to the value when it is deployed.

Related

import an existing SSM Parameter and add as an Task Image environment variable in ApplicationLoadBalancedFargateService

I have parameters in SSM that is saved looking something like /dbUrl/prod , /dbUrl/dev and so on where it is in the format /dbUrl/${stage}.
I want to get this parameter and set as an environment variable for the task definition so I have a different value for the variable based on different environment. Right now stuck on how to import an existing parameter
Also is it possible to access the DB_URL value as process.env.DB_URL inside my node.js code after I manage to set the environment variable here
Docs I was following
ApplicationLoadBalancedFargateService
ApplicationLoadBalancedTaskImageOptions#secrets
const socketService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, `socketService${props.stage}`, {
cluster: cluster,
loadBalancer: loadBalancer ,
memoryLimitMiB: 2048,
cpu: 1024,
desiredCount: 2,
listenerPort: 1111,
taskImageOptions: {
image: ContainerImage.fromAsset("../socket"),
environment: {
},
secrets: {
DB_URL: //how to import existing /dbUrl/${props.stage} from SSM
}
},
});
You linked to documentation on the secrets prop of the ApplicationLoadBalancedTaskImageOptions. The docs specify that the type of the secrets prop is { [string]: Secret }.
You can follow the link to the documentation of Secret to see how it can be obtained. You will see that it has a fromSsmParameter method, which is what you need. That method takes in an IParameter.
To import an existing String Parameter, you can use one of the from* methods defined in the StringParameter class. For example, you can use fromSecureStringParameterAttributes

Why codepipline require the KMS key?

I made the CodePipeline to build the source code from CodeCommit to ECR by cdk
When deploying this cdk code, somehow the key named like this
codepipeline-cdkmynavirepomynavipipelinefe7f8d68 is made in KMS customer managed key
I am not sure why this is made, and I don't want to use this.
Why or where this key is made?
const adminPipeline = new codepipeline.Pipeline(this, 'mynaviPipeline', {
pipelineName: 'cdk-mynavi-pl',
});
const mynavi_cc_repo_name = 'cdk-mynavi-cc'
const mynavi_cc_repo = new codecommit.Repository(this,
"mynavi-cc-repo",{
repositoryName: mynavi_cc_repo_name,
description:"for resizer repo"
})
const adminBuildProject = new codebuild.PipelineProject(this, 'adminBuildproject', {
environment: {
buildImage:codebuild.LinuxBuildImage.STANDARD_4_0,
privileged:true,
},
buildSpec: codebuild.BuildSpec.fromSourceFilename("./buildspec.yml")
});
const adminSourceOutput = new codepipeline.Artifact();
const adminSourceAction = new cdk.aws_codepipeline_actions.CodeCommitSourceAction({
actionName: 'AdminSource',
repository: mynavi_cc_repo,
output: adminSourceOutput,
trigger: cdk.aws_codepipeline_actions.CodeCommitTrigger.POLL,
})
const dockerHubSecretArn = 'arn:aws:secretsmanager:ap-northeast-1:678100228231:secret:docker_login-TBFA5B';
const dockerHubSecret = secretsmanager.Secret.fromSecretCompleteArn(this, 'SecretFromCompleteArn', dockerHubSecretArn);
dockerHubSecret.grantRead(adminBuildProject)
cronEcrRepo.grantPullPush(adminBuildProject)
djangoEcrRepo.grantPullPush(adminBuildProject)
nginxEcrRepo.grantPullPush(adminBuildProject)
const adminBuildOutput = new codepipeline.Artifact();
const adminBuildAction = new cdk.aws_codepipeline_actions.CodeBuildAction({
actionName: 'AdminCodeBuild',
project: adminBuildProject,
input: adminSourceOutput,
outputs: [adminBuildOutput]
});
adminPipeline.addStage({
stageName: "mynaviSource",
actions: [adminSourceAction],
});
adminPipeline.addStage({
stageName : "mynaviBuild",
actions: [adminBuildAction]
});
It has to do with encryption at rest.
Data in CodePipeline is encrypted at rest using AWS KMS keys. Code artifacts are stored in a customer-owned S3 bucket and encrypted with either the AWS managed key or a customer managed key.
Encrypting codepipline artifacts is enabled by default.
If you choose the default option for encrypting code artifacts, CodePipeline uses the AWS managed key. You cannot change or delete this AWS managed key.
You cannot disable the encryption, but you can choose how you encrypt the artifacts.
The good thing is that if you go with the default option, you don't have to manage the encryption keys.
This can be, for example, selected in the CodePipeline console:
More on Data Protection in AWS CodePipeline.

AWS CDK: enabling access logging for classical load balancer

We are using Classical load balancer in our Infra deployed via CDK. For deploying Load balancer we are using level 2 Constructs. The code is like this:
const lb = new elb.LoadBalancer(this, 'LB', {
vpc: vpcRef,
internetFacing: true,
healthCheck: {
port: 80
},
});
lb.addListener({
externalPort: 80,
});
}
We are not able to find any property using which we can enable the access logging. Someone suggested me to use AccessLoggingPolicyProperty. I checked that and found that this property can be used with Level 1 constructs only. Can some please guide me on how we can enable the access logs via CDK on a classical load balancer using Level 2 constructs.
As per the documentation you need S3 bucket with right permissions configured. With that you can follow aws-cdk documentation on how to get access to L1 Construct.
It is going to look roughly like the following code
const lbLogs = new Bucket(this, 'LB Logs');
const elbAccountId = 'TODO: find right account for you region in docs';
lbLogs.grantPut(new AccountPrincipal(elbAccountId));
lbLogs.grantPut(
new ServicePrincipal('delivery.logs.amazonaws.com', {
conditions: {
StringEquals: {
's3:x-amz-acl': 'bucket-owner-full-control',
},
},
})
);
lbLogs.grantRead(new ServicePrincipal('delivery.logs.amazonaws.com'));
const cfnLoadBalancer = lb.node.defaultChild as CfnLoadBalancer;
cfnLoadBalancer.accessLoggingPolicy = {
enabled: true,
s3BucketName: lbLogs.bucketName,
};

AWS CDK - Possible to access individual (JSON) value within a Secrets Manager secret when specifying secrets for a container?

I'm trying to put together a relatively simple stack on AWS CDK that involves an ApplicationLoadBalancedFargateService from aws-ecs-patterns.
My problem involves secrets. I have a secret in Secrets Manager that has several key/values (I think technically it's stored as a JSON doc, but AWS provides a key/val interface), and I need to pass them to my containers individually. I do this currently in an equivalent non-cdk (made in the console) stack by simply specifying the key, like this: arn:aws:secretsmanager:us-west-2:[acct]:secret/name-??????:KEY::, where `KEY is the secret key, and the correct value is inserted into the container as an env var.
When I try to do that with CDK, I get an error when I cdk synth:
`secretCompleteArn` does not appear to be complete; missing 6-character suffix
If I remove the last bit (:KEY::), it successfully synths, but my container isn't actually getting what I want.
This is how I'm trying to use it in my cdk (typescript) code:
new ApplicationLoadBalancedFargateService(this, 'Service', {
...
taskImageOptions: {
image: containerImage, // defined elsewhere
...
secrets: {
'DB_DATABASE': ecs.Secret.fromSecretsManager(
Secret.fromSecretCompleteArn(this, 'secret-DB_DATABASE',
'arn:aws:secretsmanager:us-west-2:[acct]:secret:secret/name-??????:KEY::')),
//there's really a few more, pulling keys from the same secret. Omitting for brevity
},
},
});
Is there a way to to make this work? Or do I need to change the way I store/use my secrets?
This is how you pass a specific key as environment variable to your container:
const mySecret = secretsmanager.Secret.fromSecretCompleteArn('<your arn>');
taskDefinition.addContainer('MyContainer', {
// ... other props ...
secrets: {
SECRET_KEY: ecs.Secret.fromSecretsManager(mySecret, 'specificKey'),
},
});
or with the ApplicationLoadBalancedFargateService:
new ApplicationLoadBalancedFargateService(this, 'Service', {
...
taskImageOptions: {
image: containerImage, // defined elsewhere
...
secrets: {
'DB_DATABASE': ecs.Secret.fromSecretsManager(mySecret, 'specificKey'),
},
},
});

How to get the AWS IoT custom endpoint in CDK?

I want to pass the IoT custom endpoint as an env var to a lambda declared in CDK.
I'm talking about the IoT custom endpoint that lives here:
How do I get it in context of CDK?
You can ref AWS sample code:
https://github.com/aws-samples/aws-iot-cqrs-example/blob/master/lib/querycommandcontainers.ts
const getIoTEndpoint = new customResource.AwsCustomResource(this, 'IoTEndpoint', {
onCreate: {
service: 'Iot',
action: 'describeEndpoint',
physicalResourceId: customResource.PhysicalResourceId.fromResponse('endpointAddress'),
parameters: {
"endpointType": "iot:Data-ATS"
}
},
policy: customResource.AwsCustomResourcePolicy.fromSdkCalls({resources: customResource.AwsCustomResourcePolicy.ANY_RESOURCE})
});
const IOT_ENDPOINT = getIoTEndpoint.getResponseField('endpointAddress')
AFAIK the only way to recover is by using Custom Resources (Lambda), for example (IoTThing): https://aws.amazon.com/blogs/iot/automating-aws-iot-greengrass-setup-with-aws-cloudformation/