Cloudformation: Reference created ACM Certificate in other region - aws-cloudformation

Since https certificates for Cloudfront can only be created in us-east-1 and my entire stack is created in eu-west-1 I wanted to create a stack in us-east-1 that contains the ACM certificate, and then use that certificate in my stack(s) in eu-west-1.
The only problem is, how do I reference this certificate without hardcoding it, as I can't ImportValue an output in another region.
e.g.
Distribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt S3Bucket.RegionalDomainName
Id: ****
CustomOriginConfig:
HTTPPort: '80'
HTTPSPort: '443'
OriginProtocolPolicy: https-only
DefaultRootObject: 'index.html'
Enabled: true
Aliases:
- 'bla.bla.com'
DefaultCacheBehavior:
TargetOriginId: '*-origin'
AllowedMethods:
- GET
- HEAD
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6'
ViewerCertificate:
AcmCertificateArn: !ImportValue ****
SslSupportMethod: sni-only
What do I need to put on the AcmCertificateArn line when I deploy this in eu-west-1?

As you've pointed out, you can't make cross-region export/import references between stacks in different regions. In this case, usually you would provide the Certificate ARN as an input parameter to your stack in eu-west-1.
The other options would involve the use of SSM parameters dynamic references to pass the value of the certificate's ARN. For fully automated solution, you would need to develop a custom resource in eu-west-1 in the form of a lambda function. The function would query the stack in us-east-1 for the arn in its outputs and return the arn to the stack in eu-west-1.

Related

AWS ApiGateaway Cloudformation: I have a problem with JWTConfiguration when creating the authorizer

Creating a Gateaway API via AWS Cloudformation I have a problem with JWTConfiguration when creating the authorizer.
Authorizer:
Type: 'AWS::ApiGatewayV2::Authorizer'
Properties:
Name: VSTORES_Api_CognitoAuthorizer
ApiId: !Ref VCloudApiGateway
AuthorizerType: JWT
IdentitySource:
- '$request.header.Authorization'
AuthorizerResultTtlInSeconds: 3600
JWTConfiguration:
Audience:
- xxxxxxxxxxxxxxxxxxxxx
Issuer: https://cognito-idp.us-east-1.amazonaws.com/us-east-xxxxxxx
I get the following error:
Property validation failure: [Encountered unsupported properties in
{/}: [JWTConfiguration]]
what am I doing wrong?
Judging by the documentation it looks like your formatting is correct. I suggest ensuring your JWT value is compliant with RFC 7519 and able to be decoded using a website similar to https://jwt.io/

How to setup Oauth scopes at AWS Serverless Function?

Issue: OAuth Scopes are empty at Method Request Settings using Cloudformation and AWS-SAM
Apparently there are a few places where I can declare my authorization scopes, if I got it right, I should declare all scopes at the authorizer and the ones I would like to specify per function at my Function template.
This is the template I am trying to fix:
MyServerlessFn
Type: AWS::Serverless::Function
Properties:
FunctionName: helloWorldFn
Description: my test using cognito.
Handler: src/handlers/helloWorld.handler
Runtime: nodejs12.x
Events:
ApplicationPostAPI:
Type: Api
Properties:
Auth:
AuthorizationScopes:
- https://foobar.acme.net/full-api
Method: POST
Path: /hello/world
RestApiId: !Ref MyServerlessApi
using sam cli I can validate, build and deploy this template but the oauthScopes are empty when I check it using AWS web console.
Here the aws doc:
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-apifunctionauth.html
I also noticed that the scopes you define on a function level stay empty.
Whether the documentation is wrong or a current AWS SAM bug I leave in the midle.
(see: https://github.com/aws/serverless-application-model/issues/1752)
However you can solve this by specifying an authorizer on the api level and refer to this authorizer on function level.
ApiGw:
Type: AWS::Serverless::Api
Properties:
Description: some description
Auth:
Authorizers:
DefaultAuthorizer:
UserPoolArn: somepool
AuthType: "COGNITO_USER_POOLS"
AuthorizerWithScopeABC:
UserPoolArn: somepool
AuthType: "COGNITO_USER_POOLS"
AuthorizationScopes:
- /ABC
AuthorizerWithScopeXYZ:
UserPoolArn: somepool
AuthType: "COGNITO_USER_POOLS"
AuthorizationScopes:
- /XYZ
DefaultAuthorizer: DefaultAuthorizer
Function:
Type: AWS::Serverless::Function
Properties:
Events:
ApiEvent:
Type: Api
Properties:
Path: /somepath
Method: get
RestApiId: !Ref ApiGw
Auth:
Authorizer: AuthorizerWithScopeABC

Certificate issue when using serverless and serverless-domain-manager with custom domain

I'm trying to set up a custom domain for my API Gateway and Lambda function.
I registered a domain with route53. Ex: myDomainToTestApi.net
I also created the certificates for: myDomainToTestApi.net, *.myDomainToTestApi.net, www.myDomainToTestApi.net
I installed the plugin serverless-domain-manager for serverless framerwork
In my serverless.yml I added (under custom):
customDomain:
domainName: myDomainToTestApi.net
basePath: ''
stage: ${opt:stage, 'dev'}
certificateName: '*.myDomainToTestApi.net'
createRoute53Record: true
ALL resources are in us-east-1
When I run:
sls create-domain
I receive the following error...
Serverless: Load command test
Serverless: Load command dashboard
Serverless: Invoke create_domain
Serverless: [AWS apigateway 404 0.374s 0 retries] getDomainName({ domainName: 'myDomainToTestApi.net' })
Serverless Domain Manager: NotFoundException: Invalid domain name identifier specified
Serverless: [AWS acm 200 0.35s 0 retries] listCertificates({ CertificateStatuses: [ 'PENDING_VALIDATION', 'ISSUED', 'INACTIVE', [length]: 3 ] })
Error --------------------------------------------------
Error: Error: Could not find the certificate *.myDomainToTestApi.net.
at ServerlessCustomDomain.<anonymous> (/Users/user/project/node_modules/serverless-domain-manager/dist/index.js:279:23)
If I go to the Certificate Manager view, the status for all is Issued
Anyone knows what could be happening...? Thanks.
Try to add another propertie called certificateArn, you can find certicateArn in the certificate manager detailed view of the domain
certificateArn: 'xxxxx'
It is actually
sls create_domain
(notice the underscore)

cloudformation validation returns: Invalid template resource property

Consider this part of a cloud formation template:
# VPC
myVPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: 10.99.99.0/24
# Security group
http_sec_group:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupName: http_in
GroupDescription: "Allow http traffic inbound"
VpcId: !Ref myVPC
SecurityGroupIngress:
- ToPort: 80
IpProtocol: tcp
Validating it returns this error:
An error occurred (ValidationError) when calling the ValidateTemplate operation: Invalid template resource property 'myVPC'
The syntax looks correct, but why does the reference return an error?
The error says "Invalid Template Resource Property". This is because your complete template file may be malformed due to spacing issues and CloudFormation is considering 'myVPC' as a property of previously declared resource.
More information on this error is available here.
Also, your security group resource Logical ID is invalid as Logical IDs need to be alphanumeric. More info.

CloudFormation to Configure API Gateway Method to use Cognito Authorizer

I'm trying to define API Gateway resources using CloudFormation. Specifically, I'm attempting to create a template for an API Gateway Resource Method that authenticates using Cognito. I've created the Authorizer, and using the console I can perform this configuration without issue (see image attached). I just can't find a way to specify the API method request authorization using the Cognito user pool. It's driving me crazy. As far as I can see, no documentation covers this.
Does anyone know if this is possible, and if so, how to do it? I realize I can achieve this using Swagger but I'm not looking forward to re-defining all of my API Gateway resources in Swagger vs. CloudFormation.
Thanks in advance!
If you are using SAM then you set the pool as a global default and mark the functions you don't want to be authenticated.
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Cors: "'*'"
Auth:
DefaultAuthorizer: MyCognitoAuthorizer
Authorizers:
MyCognitoAuthorizer:
UserPoolArn: !GetAtt MyCognitoUserPool.Arn
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./src
Handler: lambda.handler
Runtime: nodejs8.10
Events:
Root:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /
Method: GET
MyCognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: !Ref CognitoUserPoolName
Policies:
PasswordPolicy:
MinimumLength: 8
UsernameAttributes:
- email
Schema:
- AttributeDataType: String
Name: email
Required: false
MyCognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref MyCognitoUserPool
ClientName: !Ref CognitoUserPoolClientName
GenerateSecret: false
For functions you don't want to be behind cognito. Define in the events section of the AWS::Serverless::Function definition.
Events:
Root:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /
Method: GET
Auth:
Authorizer: 'NONE'
Use the AWS Sam template documentation rather than the cloudformation definitions.
I don't have a code sample handy, but here's what you will need to do:
1) Add an Authorizer resource to your template with type "COGNITO_USER_POOLS",
2) Set the authorizerId on the API method resource to the ID reference from the authorizer. Set the authorizationType on the method to "COGNITO_USER_POOLS"
As for the user pools themselves, you will need to use custom resources, at least until official support is released. There are several open-source implementations out there that you could use (here's one example: https://github.com/aws-samples/aws-api-gateway-developer-portal/tree/7d0d1e56d54e9775ee2d18907ebdf1db9dafcc06/lambdas/cognito-cloudformation-custom-resource)