Dynamically generate cloudformation resources using CDK - aws-cloudformation

I'm trying to dynamically generate SNS subscriptions in CDK based on what we have in mappings. What's the best way to do this here? I have mappings that essentially maps the SNS topic ARNs my queue want to subscribe to in each region/stage. The mapping looks something like this:
"Mappings":
"SomeArnMap":
"eu-west-1":
"beta":
- "arn:aws:sns:us-west-2:0123456789:topic1"
"gamma":
- "arn:aws:sns:us-west-2:0123456789:topic2"
- "arn:aws:sns:us-west-2:0123456789:topic3"
How do I write code in CDK that creates a subscription for each element in the list here? I can't get regular loop to work because we don't know the size of the list until deployment. After CDK synth, it would just give me tokens like #{Token[TOKEN.264]} for my topic ARN.
Is it even doable in CDK/CloudFormation? Thanks.

Since tokens aren't resolved during the runtime of aws-cdk code, usually you can use cfn intrinsic functions which declare some sort operation on the token in your template. These are accessible in #aws-cdk/core.fn. However, cfn doesn't have intrinsics for looping over values, only selecting values from a list/map.
If your cdk has these mappings in its output template and you just want to extract a value for reference when building another construct Fn.findInMap I believe should do that.
const importedTopic = Sns.Topic.fromTopicArn(this, "ImportedTopicId", Fn.findInMap("SomeArnMap", "eu-west-1", "beta"));
importedTopic.addSubscription(SomeSqsQueueOrSomething);

Related

Is there anyway to query components in an Azure Pipeline?

I know one can use REST API to query Pipeline activities but is there anyway to query Pipeline components ( i.e, listing of linked services, sources, sinks, parameters, etc.)
Right now I'm manually recording all the components I see in the pipeline and querying these components would make this listing faster and more accurate
enter image description here
Thanks, Jeannie
I haven't found a way to get all the components of a pipeline directly. If the information you want to obtain is defined in the YAML file, you cannot directly obtain it, you may need to parse the YAML file to obtain it.
If the information you want to get is defined on the UI, such as variables, you can get it through the REST API Definitions - Get. And you can get the resources of the pipeline through Resources - List.

Best Practice for Operators to Receive Secrets in custom resource

I'm not finding any answers to this on Google but I may just not know what terms to search for.
In a CRD, is there a way to define a field in the spec that is a secret (and therefore shouldn't be stored in plain text)? For example, if the custom resource needs to have an API token included in it, how do you define that in the CRD?
One thought I had was to just have the user create a Secret outside of the CRD and then provide the secret's name in a custom resource field so the operator can query it from the K8s API on demand when needed (and obviously associated RBAC needs to be configured so the operator has read access to the Secret). So the field in the CRD would just be a normal string that is the name of the target Secret.
But is there a better way? Any existing best practices around this?
You do indeed just store the value in an actual Secret and reference it. You'll find the same pattern all over k8s. Then in your controller code you get your custom object, find the ref, get that secret, and then you have your data.

Automatically rotate AppSync API key

CloudFormation provides an AWS::AppSync::ApiKey resource type for creating an AppSync API key in a CloudFormation stack. The API key will expire. Is there a simple way to define a rotation schedule within CloudFormation? I don't see anything, but it seems like such an obvious use case that I'm not sure what good the AWS::AppSync::ApiKey resource type is without it.
Currently I have a lambda that runs on a schedule to generate a new key and store it in SecretsManager. This works, but it's an extra step, and I have to run the lambda manually the first time. I am open to alternatives.
You don’t want to create an AWS::AppSync::ApiKey. Instead make a AWS::SecretsManager::Secret and a AWS::SecretsManager::RotationSchedule. The RotationSchedule will let you use a lambda to automatically rotate the ApiKey and store it in the Secret.
Ultimately, the AWS::AppSync::ApiKey is of little practical use for you because you will need to deal with the expiration.

Create a KMS custom Key in CloudFormation template for different region

Is there any way to generate a custom KMS Key via CloudFormation template in a different region than the region which is specified in the respective AWS User account you use to run the template?
Merci A
Short answer:
No, not directly.
Long answer:
It can actually be done in one of two ways. First, using StackSets, you can create a single template that will be deployed in selected accounts (1 in this occurence) and regions.
The second way to achieve your goal is to use a Custom Resource to create your KMS keys in other regions. This custom resource will invoke a Lambda function to handle the lifecycle of your KMS keys. Within this Lambda you will have to call the appropriate APIs to create/update/delete the KMS keys in the desired region.

I'd like to create CloudFormation stack with resources in multiple regions. Is this possible?

Is it possible to create a single Amazon CloudFormation stack template that instantiates an AWS::EC2::Instance in ap-southeast-1 and another AWS::EC2::Instance in us-west-2 for example?
I suspect not, but I've not yet found a definitive yes/no saying that stacks can't have resources spanning multiple regions.
The accepted answer is out of date. It is now possible to create stacks across accounts and regions using CloudFormation StackSets.
A very good question; but I don't think you would be able to create resources spread across multiple regions.
The end point URL for CloudFormation is region based and AFAIK there isn't a place whether you can specify an region specific (diff region) information.
As of today you can compose the CloudFormation template in such way to make it region independent by leveraging the mappings section and get::region function; but making the template spread across multiple regions simultaneously wouldn't be possible; but can be expected down the line.
Your best bet right now would be to use a Cloudformation Custom Resource that invokes a Lambda function in order to create the resources that are in other regions. When you run the CFN template it would invoke the Lambda function where you'd create code (Python, Node.js or Java) that leverages the AWS SDKs to create the resources you need. CFN Custom Resources allow you to pass parameters to the function and get "outputs" back from them so from a CFN perspective you can treat it just like any other resource.
Here's a walkthrough example from the AWS docs: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html
You can create a lambda function invoking to create a resource in another region, and even making your lambda function to invoke another stack in the other region.
To make your life easy, in this case you can use the lambda cli2cloudformation (https://github.com/lucioveloso/cli2cloudformation).
Using it, you can execute CLI commands inside your lambda, and by this way, you specific the --region in the command.
It's also interesting, because you will be able to set a command when your stack is created, updated and deleted.
"myCustomResource": {
"Type": "Custom::LocationConstraint",
"Properties": {
"ServiceToken": "arn:aws:lambda:eu-west-1:432811670411:function:cli2cfn_proxy2",
"CliCommandCreate": "s3api get-bucket-location --bucket my-test-bucket --region eu-west-1",
"CliCommandUpdate": "",
"CliCommandDelete": ""
}
},