How to add domain alias to existing CloudFront distribution using AWS CDK - amazon-web-services

I just deployed a CloudFormation solutions from the AWS Solutions. The solutions included a new CloudFront distribution. My challenge is that I want to add a custom domain mysite.example.com to the dxxxxxx.cloudfront.net distribution. I already created an alias and certificate using Certificate Manager. My question is how do I add a new domain to the existing CloudFront.
I understand that we can import an existing distribution using Distribution.fromDistributionAttributes.
for example
const distribution = cloudfront.Distribution.fromDistributionAttributes(this, 'ImportedDist', {
domainName: 'd111111abcdef8.cloudfront.net',
distributionId: '012345ABCDEF',
});
Let's say I have the alias domain name and certificate ARN ready to use.
const domainName = 'mysite.example.com';
const certificateArn = 'arn:aws:acm:us-east-1: 123456789012:certificate/abcdefgh-1234-5678-9012-abcdefghujkl';
Where do I go from here?

Add your domain and certificate by updating your "AWS solutions" CDK app. CDK apps are designed be modified and redeployed.
The Distribution construct accepts the certificate?:ICertificate and domainNames?: string[] as props to the constructor.
Instances also expose a addBehavior(pathPattern, origin, behaviorOptions?), which seems handy.
If the app is in production, be mindful that updates sometimes result in resource replacement or interruption.
The CloudFormation docs note the update behaviour for each service property. In the happy case you will see Update requires: No interruption. Run the cdk diff command to preview the changes
CloudFormation will make to your resources.
What about cloudfront.Distribution.fromDistributionAttributes? Many CDK classes have static from... methods
to get a reference to an existing AWS resource. These methods are handy (or even necessary) when resources are shared between apps, but should be used only when you cannot modify the original CDK construct.

Related

how to get existing AWS arn certificate in order to use it in serverlessframework

is there a way , to get existing AWS certificate ARN , when i am in my serverless framework deployment file , i need a way to get the arn of the certificate when i know only the name of the certificate
You can usually infer the the entire structure of ARN's inside AWS. For example this is the ARN of a DynamoDB table in my AWS account (the X's are my account ID):
arn:aws:dynamodb:us-east-1:XXXXXXXXXXX:table/awesome-mytable-dev
These ARN's are the same structure every time:
arn:aws:[service name]:[region name or blank]:[accountID]:[entity
within the service]/[name of entity]
Try manually creating a certificate, then seeing how the ARN is structured, then just "build" the ARN you need to match the same structure. Recent versions of the Serverless Framework even allow you to add in your AWS information as variables using ${aws:region} or ${aws:accountId}.

AWS CDK update/add lifecycle to existing S3 bucket using custom source

I created an S3 bucket but now I would like to update/add lifecycle policies to it using CDK.
Currently I can import this bucket to a new stack file.
const testBucket = s3.Bucket.fromBucketAttributes(this, 'TestBucket', {
bucketArn: 'arn:aws:s3:::xxxxxx'});
How can I use AwsCustomResource to update/add lifecycle policies? For example, for prefix = long, I want those objects to expire in 7 days, and for prefix = short, I want them to expire in 3 days.
Or is there a general way of updating an existing S3 bucket in a new stack with CDK?
The best option for this is probably to add it to the stack using resource importing. Don't confuse a custom resource with a CDK construct. A custom resource involves deploying a lambda function and calling that function when the CloudFormation custom resource is present in your stack. A CDK construct is used to generate a CloudFormation template. It allows you to combine different resources into a single bit of code, and allows some logical decisions based on the input values.
Steps to import:
Make sure your current CDK is what is deployed. You cannot import resources when there are other changes.
Add the S3 bucket to your CDK code as if you were creating it for the first time. Make sure that all the settings are the same as what is currently deployed. This is important because the import process doesn't validate that what you have configured matches what you are importing.
Run cdk synth to generate the CloudFormation template that includes the S3 bucket.
In the CloudFormation console locate the stack that represents the CDK stack you are working with.
Select Import resources into stack from the Stack actions menu.
Follow the prompts. When asked for the template select Upload a template file and select the template created by the cdk synth command (hint: it will be in cdk-out). You will be prompted to add the bucket name. This should be the bucket that you are wanting to add to this stack.
Once that is done you can modify the bucket as if it were created by your stack.
One thing to note. CDK includes some meta-data in the CloudFormation template. This value must be the same as what is currently deploy or it will be seen as a change and you won't be able to perform the import. You can copy the values from what is currently deployed and manually edit the template created by cdk synth to match that.
Need to access the CfnBucket reference of the testBucket and add lifecycle rules to it.
const testBucket = s3.Bucket.fromBucketAttributes(this, 'TestBucket', {
bucketArn: 'arn:aws:s3:::xxxxxx')
testBucket.node.root.addLifecycleRule({prefix: 'short', expiration:3, enabled:true})
testBucket.node.root.addLifecycleRule({prefix: 'long', expiration:7, enabled:true})

How can I deploy lambda#edge code in an organisation's Cloudfront instances via aws cli?

We have a Cloudfront distribution in front of some AWS buckets, set up by another member of my team.
I have some node.js code for lambda#edge to rewrite requests.
My question is how do I deploy it to Cloudfront for those buckets, using the aws command-line tool?
I think, it would require
request perms to assume a role;
deploy the function somewhere that it can be used (as opposed to just my account);
create the role/trust relationship;
create the behaviour in Cloudfront;
and associate the function with a Viewer Request event.
I have not found any coherent documentation or examples of how to do all of this, let alone using the aws tool.
As it is, I cannot see the Cloudfront or S3 buckets when I log in via the web site, though I can list the s3 bucket contents via command-line. (I am unsure how to access the Cloudfront via command line).
If you have your function deployed in Lambda then you should add it to the "LambdaFunctionAssociations" element of the CloudFront distribution config then update your config using the update-distribution CLI command like:
aws cloudfront update-distribution --id C123456789 --distribution-config file://local/path/to/distrib-config.json
Where id is the ID of your distribution
If you want to get the current CloudFront distribution config you can do aws cloudfront get-distribution-config --id C123456789
If you want to create the function first then aws lambda create-function will return the created functions ARN to pass into the config. https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html
When you say "just to my account", do you mean a separate AWS account or do you mean using your IAM user in the same AWS account as the CloudFront distribution and S3 buckets? It sounds like your AWS Console user is different to the user that has the access keys set in aws cli. aws cloudfront list-distributions will let you see CloudFront via command line.
Link to AWS Dev Guide for programmatic lambda#edge

Can I move an AWS Lambda site to a private domain?

I'm using Zappa to deploy a Flask app. It works (site). Obviously I'd like to not have it stuck behind the aws domain and put it on my personal domain.
Everything I'm searching keeps talking about hosting a Lambda site with S3 and API Gateway. Is there no way to just deploy my little app to a custom domain?
Edit
Following #mislav's answer, I was able to get my google domain working with AWS. But when I try to finish by running zappa certify I get an error about the domain existing:
raise error_class(parsed_response, operation_name)
botocore.errorfactory.BadRequestException: An error occurred
(BadRequestException) when calling the CreateDomainName operation: The
domain name you provided already exists.
My zappa_settings.json is
{
"dev": {
"app_function": "ping_app.app",
"aws_region": "us-west-1",
"profile_name": "Breuds",
"project_name": "breuds",
"runtime": "python3.6",
"s3_bucket": "zappa-ping-redshift",
"slim_handler": true,
"certificate_arn": "arn:aws:acm:us-east-1:010174774769:certificate/3a92c204-5788-42fc-bc65-74aaae8c1b3f",
"domain": "breuds.com"
}
}
I am beginning to think I am doing something convoluted on my domain side. I'm using Google Domains (since I have a custom domain for my email, just using that), but that seems to cause a headache trying to get AWS to talk to it.
It’s actually explained in zappa’s readme.
Deploying to a Domain With AWS Certificate Manager
Amazon provides their own free alternative to Let's Encrypt called AWS Certificate Manager (ACM). To use this service with Zappa:
Verify your domain in the AWS Certificate Manager console.
In the console, select the N. Virginia (us-east-1) region and request a certificate for your domain or subdomain (sub.yourdomain.tld), or request a wildcard domain (*.yourdomain.tld).
Copy the entire ARN of that certificate and place it in the Zappa setting certificate_arn.
Set your desired domain in the domain setting.
Call $ zappa certify to create and associate the API Gateway distribution using that certificate.
There are also instructions to use your existing certificate etc.
Don’t let it fool you, the title of the section makes it sound like it’s only about certificates, but there are detailed instructions regarding using you own domain.
Edit:
I’m including my own zappa settings for reference.
{
"common": {
"app_function": "app.__hug_wsgi__",
"aws_region": "eu-central-1",
"s3_bucket": "excuse-generator",
"profile_name": "mislavcimpersak",
"remote_env": "s3://excuse-generator/secrets.json",
"certificate_arn": "arn:aws:acm:us-east-1:500819636056:certificate/3edb9c1c-12c5-4601-89a9-dc42df840fa6"
},
"prod": {
"extends": "common",
"domain": "function.xkcd-excuse.com"
},
"dev": {
"extends": "common",
"debug": true,
"keep_warm": false,
"domain": "function-dev.xkcd-excuse.com"
}
}
Step by step guide for domain bought on namecheap.com and served through cloudflare.com
buy domain on namecheap.com/use existing
register new site on cloudflare.com/use existing
cloudflare will give you (most probably) two nameservers
enter under https://ap.www.namecheap.com/domains/domaincontrolpanel/xkcd-excuse.com/domain DNS - choose "Custom DNS" nameservers given on cloudflare
go to AWS ACM and request a new certificate (certificate must be created in us-east-1 region)
enter if necessary multiple subdomains (foo.example.com & foo-dev.example.com)
make note of ACM ARN given from AWS management console
in zappa_settings.json enter under certificate_arn your ARN
in zappa_settings.json under route53_enabled put false - this is a must
in zappa_settings.json under domain enter domain for each stage ie. foo.example.com and foo-dev.example.com
run zappa certify <stage_name>
it should say: "Created a new domain name with supplied certificate. Please note that it can take up to 40 minutes for this domain to be created and propagated through AWS, but it requires no further work on your part.
Certificate updated!"
go to CloudFlare DNS interface and enter
CNAME: foo - i3jtsjkdeu4wxo.cloudfront.net
CNAME: foo-dev - d2jtsjkdeu4wxo.cloudfront.net
wait for 40 minutes and check your domain(s), they should serve your Lambda function
You might not need API Gateway. It will depend on site functionality. You can host a static website using S3 with a custom domain. You can include client-side javascript(angular/react etc..) API Gateway is really for handling http requests and passing it on to defined resources(Lambda or others).
If your site will require backend capability then you have few options.
1) Build lambda functions and then use API Gateway(REST API) to interact with these functions.
yourhostname.com -> S3 -> API Gateway(aws hostname) -> lambda
2) Use AWS JS SDK to interact with your lambda functions directly.
yourhostname.com -> S3 -> AWS SDK -> lambda
3) Use API Gateway and then forwarding to Lambda or self hosted web server(flask node) using EC2 instance
yourhostname.com -> API Gateway(aws hostname) -> lambda
yourhostname.com -> self hosted web server
Here is a picture that might make it a bit clearer.
Correct me if I am wrong flask is used for backend development to build microservices. To host it you would use either build lambda functions or host it on your own instance.
https://andrich.blog/2017/02/12/first-steps-with-aws-lambda-zappa-flask-and-python/
Let me know if this helps.

Is it possible to add NotificationConfiguration to an existing S3 buckets using CFT?

I am still a newbie with AWS services.
I would like to add a Lambda trigger on an existing S3 bucket using a CloudFormation template (CFT). Is this possible?
The following CFT is attempting to create a new S3 bucket and add an event notification on it.
S3BUCKET_NOTIFCATION = Bucket(
"S3Bucket",
BucketName=s3_bucket("confidential", Ref(ENV)),
NotificationConfiguration=NotificationConfiguration(
LambdaConfigurations=[
LambdaConfigurations(
Event="s3:ObjectCreated:*",
Filter=Filter(
S3Key=S3Key(
Rules=[Rules(Name="prefix", Value=Ref(inputKeyPrefix)),
Rules(Name="suffix", Value=".json")]
)
),
Function=Ref(cost_function)
)
]
)
)
Is it possible to add the NotificationConfiguration to an existing bucket?
As noted by others this is still not allowed for various reasons.
Option 1) recommended
The ideal approach here, IMHO, would be to first import existing cloud resources (S3 in this case) to be managed by IaC/CloudFormation. Then, once the resource has been imported, you can add the NotificationConfiguration to your CloudFormation template. This approach allows you to manage existing resources that maybe were initially provisioned manually to be managed via IaC/Cfn moving forward.
Option 2) what you asked for
If you want to add NotificationConfiguration to an existing S3 bucket via CloudFormation the workaround is to use
a Lambda-backed custom resource created... The custom resource
triggers a Lambda function, which triggers the PutBucketNotification
API to add a notification configuration to your S3 bucket.
details here
NOTE: Please take into account the limitations with Option 2). Some of which are documented in the referenced link.
I've been unable to add NotificationConfiguration to an existing bucket as well. When you try, you'll get the error CREATE_FAILED. Reason: S3_BUCKET already exists.
This ServerFault question from 2013 details that modification of a pre-existing bucket is not allowed. It appears to still be correct.