I'm using AWS CloudFormation to create an IoT Thing, Policy and Certificate. My stack creates successfully, however, I can't access the certificate file that CloudFormation creates.
Looking at the aws docs here the only output you can get from the certificate via CloudFormation is the ARN and the Certificate ID. However, there is no way to retrieve your certificate using the ARN or Certificate ID that I can see.
If you upload your certificate signing request (CSR) via the AWS IoT Console, it displays a download link that you can get your certificate file.
Unfortunately I need to use CloudFormation to create the IoT Certificate. However it looks like you can download the certificate after it's been created. Specifically it states:
Certificates can be retrieved at any time
I have been unsuccessfully scouring the docs and web interface to figure out how I can download my certificate "at any time". I'm relatively new to the whole world of certs and private keys so hopefully I missed something easy.
Does anyone know if it is possible to get your certificate from an IoT Certificate created by CloudFormation?
Certificates created using CloudFormation (Via a CSR) can be retrieved via the following ways
Aws IoT webpage
Just navigate to Security - Certificates, click on ... and select Download.
AWS CLI
As you mention the CLI is also an option
aws iot describe-certificate --certificate-id fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd3
Will return
{
"certificateDescription": {
"certificateArn": "arn:aws:iot:eu-central-1:xxxxxx",
"status": "ACTIVE",
"certificateId": "fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd3",
"lastModifiedDate": 1519840881.49,
"certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDsTCCApmg.....VsAzFQ==\n-----END CERTIFICATE-----\n",
"transferData": {},
"ownedBy": "123456789",
"creationDate": 1519840820.888
}
Amazon IoT SDK
Can also be used to retrieve the certificate content (PEM format) as a String based on a certificate ID (that you can output via cloudformation)
import com.amazonaws.services.iot.AWSIot;
import com.amazonaws.services.iot.AWSIotClientBuilder;
import com.amazonaws.services.iot.model.DescribeCertificateRequest;
import com.amazonaws.services.iot.model.DescribeCertificateResult;
DescribeCertificateRequest describeCertificateRequest = new DescribeCertificateRequest();
describeCertificateRequest.setCertificateId("fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd371fcd3");
DescribeCertificateResult describeCertificateResult = awsIot.describeCertificate(describeCertificateRequest);
describeCertificateResult.getCertificateDescription().getCertificatePem();
AFAIK it is not possible to output it as a variable within a cloudformation template.
Ah I found a way using the AWS CLI. But there really needs to be a way to get it via CloudFormation :(
http://docs.aws.amazon.com/cli/latest/reference/iot/describe-certificate.html
Related
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}.
I am using AWS Secret Manager Service to retrieve some confidential information like SMTP details or connection strings. However, to get secret value from AWS Secret Manager Service it seems like we need to pass the Access key and secret key apart from which secret we want to retrieve. So I am maintaining those values in config file.
public AwsSecretManagerService(IOptions<AwsAppSettings> settings)
{
awsAppSettings = settings.Value;
amazonSecretsManagerClient = new AmazonSecretsManagerClient
(awsAppSettings.Accesskey, awsAppSettings.SecretKey, RegionEndpoint.GetBySystemName(awsAppSettings.Region));
}
public async Task<SecretValueResponse> GetSecretValueAsync(SecretValueRequest secretValueRequest)
{
return _mapper.Map<SecretValueResponse>(await amazonSecretsManagerClient.GetSecretValueAsync(_mapper.Map<GetSecretValueRequest>(secretValueRequest)));
}
So I am thinking I am kind of defeating the whole purpose of using secret manager by maintaining the AWS credentials in app settings file. I am wondering what is the right way to do this
It is not a good practice to pass or add AWS credentials of an IAM User (access key and secret access key) in the code.
Instead, don't pass it and update your code as follows:
amazonSecretsManagerClient = new AmazonSecretsManagerClient
(RegionEndpoint.GetBySystemName(awsAppSettings.Region));
Question: Then how would it access the AWS services?
Answer: If you are going to execute your code on your local system, install and configure AWS CLI instead of passing AWS credentials via CLI or Terminal, it will use those AWS configured credentials to access the AWS services.
Reference for AWS CLI Installation: Installing the AWS CLI
Reference for AWS CLI Configuration: Configuring the AWS CLI
If you are going to execute your code on an AWS service (e.g., EC2 instance), attach an IAM role with that AWS resource (e.g., EC2 instance) having sufficient permissions, it will use that IAM role to access the AWS services.
I have an APNS sandbox certificate as a .p12 file and a password. I see no way to upload it using the AWS Console. There is a method documented in the CLI that should allow it:
https://docs.aws.amazon.com/cli/latest/reference/pinpoint/update-apns-sandbox-channel.html
However, it needs a certificate and private key as separate string parameters. I've tried to separate them using OpenSSL, however each time I get the following error message:
An error occurred (BadRequestException) when calling the UpdateApnsChannel operation: The certificate provided is not a valid Apple certificate
Is there a way to use sandbox certificate with Amazon Pinpoint?
Finally, I was able to do it by hijacking AJAX requests in AWS console when trying to upload a certificate. The JSON body contains privateKey and certificate parameters that can be used with a CLI command.
aws pinpoint update-apns-sandbox-channel --cli-input-json "file://path-to-request-object.json"
The request object file looks like this:
{
"APNSSandboxChannelRequest": {
// Both certificate and private key are copied from AJAX request from AWS console
"Certificate": "-----BEGIN CERTIFICATE-----\n......\n-----END CERTIFICATE-----\n",
"PrivateKey": "-----BEGIN PRIVATE KEY-----\n.....\n-----END PRIVATE KEY-----\n"
"Enabled": true
},
"ApplicationId": "app-id-here"
}
I need to get a list of the IAM policies attached to an AWS IoT Thing's certificate, in way that is script/automation-friendly. I have searched through the documentation website and the man pages, but didn't find a command that seemed to achieve this (e.g.: aws iot describe-certificate does not include this in it output).
Is there a way to achieve this with the AWS CLI?
You can get thing's certificate and policy attached to that certificate by running the following two commands of AWS CLI:
aws iot list-thing-principals --thing-name [Name of your IoT Thing]. This command will return the Certificate ARN attached to your thing.
aws iot list-principal-policies --principal [Certificate ARN]. This command will return the policies attached to the certificate.
I assume you actually mean IoT policies. Use the list-principal-policies api call to list the IoT policies attached to a certificate.
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.