-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aws cdk don't provide a way to create secrets with specified values #5810
Comments
+1 to this. I had to drop down to the L1 Construct to create a Secret with a specific value (i.e. a Lambda CR that creates an EC2 KeyPair, then put the SecretKey into SecretsManager via cfn) |
+1 too to create a SecretString in addition of the generateSecretString Props. |
+1 |
1 similar comment
+1 |
please don't add comments with just "+1". Use the 👍 on the original issue so that we can better track the number of users who want this and it keeps the comment section clean for discussion of the issue. |
+1 (yes, I did 👍 the main ask too :)). For Greengrass we have the need to send secrets locally to the secrets manager services, and based on the edge use-case, need to provide specific values and not randomly generated ones. |
we need this for the scenario:
hence, either cloudformation provide a way to inject secrets directly to |
Enables customers to supply their own secret value in the cases where an auto- generated value is not viable. This exposes the secret value in the cdk output, and CloudFormation template, but not CloudWatch/CloudTrail. fixes #5810
Enables customers to supply their own secret value in the cases where an auto- generated value is not viable. This exposes the secret value in the cdk output, and CloudFormation template, but not CloudWatch/CloudTrail. fixes #5810 ---- **PR Notes:** 1. Any feedback / thoughts on how else (besides the docstring) to warn folks of the implications of this approach? 2. The secret string can either be a plain string or string representation of a JSON value. I briefly toyed with creating `secretString` and `secretValueJson` or something, and only allowing one or the other, but wasn't sure it was better. Suggestions on this interface welcome. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
#9594 closed this issue, but then #9610 reverted it. I wanted to share the rationale on this issue for those that have been waiting for the functionality. Supplying the secretString directly in the CDK exposes the secret in all of the CDK outputs ( The preferred guidance is to use the AWS SDK/CLI/console to store these secrets, and then import them into you CDK app. If you still want to achieve the same effect, you can always either use escape hatches or write your own construct. // Escape hatch approach
const secret = new secretsmanager.Secret(stack, 'Secret');
const cfnSecret = secret.construct.defaultChild as secretsmanager.CfnSecret;
cfnSecret.generateSecretString = undefined;
cfnSecret.secretString = 'mynotverysecuresecret'; |
Libraries like react use abnormally long property names for properties that are insecure, like dangerouslySetInnerHTML. Maybe it would be a good idea to do something similar, if it's that dangerous. |
The decision just to revert the ability to provide a secret string on secret creation is quite unsatisfying. First the decision is not documented. It took me a while to get to the reasoning here, after I read the CDK API documentation, the CDK code and searching the open and closed issues. I was short before creating a feature request. Furthermore the documentation explicitly says to use the aws_secretsmanager to store secret strings in AWS:
So currently there seems no viable solution to store a secret string in AWS with CDK. Instead of reverting the feature, wouldn't it be possible to implement another feature which let CDK hide sensitive content? |
As stated in #5810 (comment), there is an option (using escape hatches); we intentionally want to keep some friction here given the potentially dangerous consequences of this approach. The other approach is to use the Secrets Manager via the console, SDK, or CLI to store the secret, then import the secret using the CDK. |
I have similar case as @clafollett. I need to store IAM user credentials for Jenkins deployment in the AWS Secrets Manager. @njlynch Do you have an example of #5810 (comment) workaround for Python? |
Ah here we go. Another one of those problems fabricated by CDK. Lovely. Just feed in the secrets via CloudFormation parameters with NoEcho option. Use a dummy value if you can't feed in optional values during CICD process and change it afterwards. Otherwise feed it once on first deploy. But hey, feel free to sit around and assume CDK users are idiots who's going to hard code password into templates when using Secrets Manager. Better remove the environment variables in lambda/task definition while at it. You never know when people are going to hard code passwords in there. @damian-keska-f @clafollett just use the L1 to create the secret and pass in the value. It works perfectly fine. You wasting your time screwing around with the L2 (as usual). |
@SleeperSmith That can be dangerous depending on how you use the secret. Refer from this block from the CloudFormation docs:
My recommendation is to use application layer encryption with a password stored in secret manager. Here's an example: // You must create this beforehand
const yourPasswordSecretArn =
"arn:aws::secretsmanager:us-east-1:123456789012:secret:example/MyExample"
// Fetch this value sometime before you start uploading
const yourPassword = getFromCertificatManager(yourPasswordSecretArn)
// Get the unecrypted secret value
const yourSecret = fs.readFileSync("/path/to/unencrypted.secret")
// Create a place for your uploaded secret to live
const uploadedSecert = new cdk.aws_secretsmanager.Secret(this, "UploadedSecret", {})
// This is where your encrypted secret is uploaded before it is parsed
const secretBucket = new cdk.aws_s3.Bucket(this, "SecretBucket", {
/* ... */
})
// This function decrypts your secret on the server
const decryptAndStoreLambda = new cdk.aws_lambda.Function(this, "DecryptAndStoreFunction", {
code: cdk.aws_lambda.Code.fromAsset("/path/to/decryptAndStore.js"),
handler: "decryptAndStore.handler",
runtime: cdk.aws_lambda.Runtime.NODEJS_14_X,
})
// Your lambda should be able to write the secert to it's new home
uploadedSecert.grantWrite(decryptAndStoreLambda)
// Your lambda will need to be able to decrypt the secert
uploadedSecert.addToResourcePolicy(
new cdk.aws_iam.PolicyStatement({
actions: ["secretsmanager:GetSecretValue"],
effect: cdk.aws_iam.Effect.ALLOW,
resources: [yourPasswordSecretArn],
}),
)
// Ensure your lambda is called whe the secret is uploaded
secretBucket.addEventNotification(
cdk.aws_s3.EventType.OBJECT_CREATED_PUT,
new cdk.aws_s3_notifications.LambdaDestination(decryptAndStoreLambda),
)
// Encrypt your seceret before it gets uploaded
const deploymentAsset = cdk.aws_s3_deployment.Source.asset("/path/to/empty/directory", {
bundling: {
command: ["sh", "-c", 'echo "Docker build not supported. Please install go."'],
image: cdk.DockerImage.fromRegistry("alpine"),
local: {
tryBundle(outputDir: string, options: BundlingOptions) {
fs.writeFileSync(
path.join(outputDir, "encrypted.secret"),
encryptYourSecret(yourSecret, yourPassword),
)
return true
},
},
},
})
// Upload your secret
new cdk.aws_s3_deployment.BucketDeployment(this, "SecretUpload", {
destinationBucket: secretBucket,
sources: [deploymentAsset],
}) This way you know that the only person that has access to your secret is someone with read access to secret manager. You could even go further, and store a public key locally in a |
I know it is probably not a best solution, but working one. credentials = CfnAccessKey(self, id=USER_ACCESS_KEY_OBJECT_ID, user_name=user.user_name)
CfnSecret(
self,
id=SECRET_OBJECT_ID,
name=SECRET_OBJECT_ID,
description='API access',
secret_string=json.dumps({
'API_USER': access_key.ref,
'API_PASSPHRASE': access_key.attr_secret_access_key
})
) |
How come there is a way to create a secret, but no easy way to set it's value? How do you expect one to even use this feature? Let me show you how your competitors do it: Just check this out! Now that's a solid reason to choose Azure over AWS. |
@makemefeelgr8 Make a secret. Make a lambda. Give it a role with write access to the secret. Pass the secret ARN as an ENV variable. Start the lambda to populate the secret. Also, your example comparing apples and oranges. CDK is not the CLI interface. It's a template generator. If you want to use the AWS CLI like in your example, the command is |
I'm coming at this from a perspective of using Mozilla Sops which allows to store the encrypted secrets in the same repo as the rest of the infra. Both CI as well as devs who should be able to update the secrets get access to the KMS key used for encryption. If this makes sense, I'm happy to try my hand at a PR for the token support. |
So, basically, what you're suggesting is to spend few days on research and write like 500 lines of code to just store a setting securely. Really? Here is a no-brainer:
Why should an end user care about writing lambda functions if all they want is to store 1 value securely?! And don't even start talking about security. Let me tell you what an average user would do in case they can't get it to work. Noone is going to spend days figuring out how to implement all those hacks you've mentioned. They'll just hardcode a value in code. Yes, that's right! And add a TODO comment with a link to this issue on github: "todo: store password in aws (if they ever implement support for it)". Man, I really wish devs would care about user feedback. |
Why are you so confrontational? If you don't care about leaking secret values in Cfn template, there is a workaround available: #5810 (comment) |
@makemefeelgr8 First off, chill the hell out. I took the time out of my day to answer your question, and I don't see why I that deserves some random person whining at me that it's too much work. If you don't like the answer then submit a PR. That's what I do whenever there's a feature missing in a framework I use. It's far more effective than complaining. Second, you can scroll up a few comments where I literally have a snippet of almost all the code you need to do this. It's far from 500 lines, and it certainly doesn't need "a few days of research." Third, you're working on an cloud based infrastructure. Research is literally part of the job, as is coding. If you don't like this then you might be in the wrong line of work. Fourth, as someone else has already pointed out, there is a perfectly serviceable workaround if you're fine with having secrets in your CF template. What more, this workaround was posted in the comment prior to yours, so you could have saved a lot of time if you did a few minutes of research. Fifth, the reason that they made it hard to put secrets in the template is to avoid exactly the scenario you outlined. Sixth, this repo literally has thousands of issues open, with PRs getting merged constantly. Clearly they care about user feedback enough to run a huge open source project to simplify a process that used to be much, much more painful than it is now. I understand being annoyed that things don't get fixed as quickly as you'd like, but they are running a huge system used by countless organizations big and small. A single user complaining at the bottom of a nearly 2 year old issue probably isn't going to be super high priority. I for one appreciate the fact that the rest of us have at least some say in the process. |
I'm not that good at English, sorry about that. Somehow, it sounded perfectly normal in my head.
I totally would, if it was a free open source project without a multi-billion corporation behind it. AWS is neither free, nor cheap. |
That's exactly the use case I have written https://github.com/taimos/secretsmanager-versioning for. Also, you need to think about versioning, what this does for you, to make sure to handle updates to secrets correctly. |
The "escape hatch" listed above no longer works.
results in
What does seem to work is to instead use
So the updated hack would be:
AWS folks - appreciate the friendly engagement on this issue, but I have to stress how frustrating this is to us. We're trying to do the right thing and store data in secrets in a programmatic way, and the response from CDK feels like "lol nope." |
Dirty hacks we've used have just stopped working... Will this get addressed, like, ever? Any updates? Anyone? Please? |
Just to copy what @njlynch said above, it's very easy to accidentally leak your secrets when specifying the value, because the value will be present in the generated CloudFormation templates, outputs of commands, and others. I won't rehash the discussion here, but the team does not plan on changing this in the future. Of course, CDK always lets you go down to the L1 construct if you want to. Here's an example stack for CDK v2: import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CfnSecret } from 'aws-cdk-lib/aws-secretsmanager';
export class TestStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const mySecret = 'I-promise-I-will-not-put-my-secrets-in-my-source-code';
new CfnSecret(this, 'my-very-insecure-secret', {
description: 'This secret is visible in the cloudformation template!',
secretString: mySecret,
});
}
} This should produce: Resources:
myveryinsecuresecret:
Type: AWS::SecretsManager::Secret
Properties:
Description: This secret is visible in the cloudformation template!
SecretString: I-promise-I-will-not-put-my-secrets-in-my-source-code
Metadata:
aws:cdk:path: TestStack/my-very-insecure-secret |
|
Enables customers to supply their own secret value in the cases where an auto- generated value is not viable. The secret value is typed to highlight the inheret lack of safety with creating secret values via CloudFormation; if a plaintext secret is provided, this secret will be visible anywhere the CloudFormation template is, including the AWS Console, SDKs, and CLIs. An unsafe `fromUnsafePlaintext` method and slightly safer `fromToken` method are exposed to highlight the potential risks and hopefully encourage safe usage. The latter is intended to be used directly with a Ref or GetAtt call from another (Custom) Resource, such as storing the value of a User SecretAccessKey or storing a password generated from a custom resource. As an implementation detail, this API has been created using the new standard for experimental APIs, via suffixing with `Beta1`. This allow us to make breaking changes by deprecating the `Beta1` version and creating an improved `Beta2` version. I've chosen to do this in this case because this has been a relatively controversial feature to decide to implement, and the criteria for what makes a secret "safe" may evolve over time. I am open to feedback on whether this is necessitated. fixes #5810
@njlynch Man, you're my hero! The bug was hanging there for 2 years and you've just fixed it. Thanks! |
Enables customers to supply their own secret value in the cases where an auto- generated value is not viable. The secret value is typed to highlight the inheret lack of safety with creating secret values via CloudFormation; if a plaintext secret is provided, this secret will be visible anywhere the CloudFormation template is, including the AWS Console, SDKs, and CLIs. An unsafe `fromUnsafePlaintext` method and slightly safer `fromToken` method are exposed to highlight the potential risks and hopefully encourage safe usage. The latter is intended to be used directly with a Ref or GetAtt call from another (Custom) Resource, such as storing the value of a User SecretAccessKey or storing a password generated from a custom resource. As an implementation detail, this API has been created using the new standard for experimental APIs, via suffixing with `Beta1`. This allow us to make breaking changes by deprecating the `Beta1` version and creating an improved `Beta2` version. I've chosen to do this in this case because this has been a relatively controversial feature to decide to implement, and the criteria for what makes a secret "safe" may evolve over time. I am open to feedback on whether this is necessitated. fixes #5810 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
|
Enables customers to supply their own secret value in the cases where an auto- generated value is not viable. The secret value is typed to highlight the inheret lack of safety with creating secret values via CloudFormation; if a plaintext secret is provided, this secret will be visible anywhere the CloudFormation template is, including the AWS Console, SDKs, and CLIs. An unsafe `fromUnsafePlaintext` method and slightly safer `fromToken` method are exposed to highlight the potential risks and hopefully encourage safe usage. The latter is intended to be used directly with a Ref or GetAtt call from another (Custom) Resource, such as storing the value of a User SecretAccessKey or storing a password generated from a custom resource. As an implementation detail, this API has been created using the new standard for experimental APIs, via suffixing with `Beta1`. This allow us to make breaking changes by deprecating the `Beta1` version and creating an improved `Beta2` version. I've chosen to do this in this case because this has been a relatively controversial feature to decide to implement, and the criteria for what makes a secret "safe" may evolve over time. I am open to feedback on whether this is necessitated. fixes aws#5810 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
For anyone stumbling across this and using the Python version of the AWS CDK: you need to use the For example in this code, I have a file called
|
I've created this open-source CDK Construct you can use to embed encrypted ciphertext into your code, and it will securely decrypt and set a value in the secret without exposing the secret to the stack output: https://github.com/nickwillan/cdk-encrypted-secret. I hope this helps. |
In the link below it's specified in the docs that we can create secrets from a JSON file containing the values of the secrets.
Unfortunately, I don't find a way to do this with aws cdk. The create-secret method doesn't accept values of the secrets themselves and code like below will autogenerate a secret.
Secrets manager docs from CLI:
https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/create-secret.html#examples
AWS CDK secrets manager docs:
https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html
The text was updated successfully, but these errors were encountered: