How to make a regional cluster in GKE w/ deployment-manager? - google-cloud-platform

"zone" is a required field when I try to create but it says in the documentation that it is "deprecated". This is kinda misleading. Then everytime I include "zone". It is the one followed; Let us say I put "asia-east2-a" then it will be a zonal where the master node is in asia-east2-a.
Below is my jinja template
resources:
- name: practice-gke-clusters
type: container.v1.cluster
properties:
zone: asia-east2-a
cluster:
name: practice-gke-clusters
location: asia-east2
network: $(ref.practice-gke-network.selfLink)
subnetwork: $(ref.practice-gke-network-subnet-1.selfLink)
nodePools:
- name: default-pool
config:
machineType: n1-standard-1
diskSizeGb: 10
diskType: pd-ssd
preemptible: True
oauthScopes:
- https://www.googleapis.com/auth/compute
- https://www.googleapis.com/auth/devstorage.read_only
- https://www.googleapis.com/auth/logging.write
- https://www.googleapis.com/auth/monitoring
initialNodeCount: 1
autoscaling:
enabled: True
minNodeCount: 1
maxNodeCount: 100
management:
autoUpgrade: False
autoRepair: True
loggingService: logging.googleapis.com
monitoringService: monitoring.googleapis.com

Currently v1 API does not support the creation of regional clusters. However you can use v1beta1 API which supports this feature and use the following resource type:
type: gcp-types/container-v1beta1:projects.locations.clusters
Rather than using the 'zone' or 'region' key in the YAML, you would instead use a parent property that includes locations.
So your YAML would look something like this (replace PROJECT_ID and REGION with your own).
resources:
- type: gcp-types/container-v1beta1:projects.locations.clusters # previously container.v1.clusters
name: source-cluster
properties:
parent: projects/PROJECT_ID/locations/REGION
cluster:
name: source
initialNodeCount: 3

Related

Google deployment manager fails when the MIG (managed instance group) and the load balancer are in the same config file

I'm working on IaC (Goole Deployment Manager - Python and YAML) and tinkering with Google's external load balancer. As part of the PoC I created:
An instance template based on ubuntu with startup script installing apache2 and an index.html file.
Create an instance group based on the above template.
Place an external HTTP load balancer in front of the instance group.
A network and a firewall rule to make debugging easier.
I heavily borrowed from Cloud Foundation Toolkit, and I'm showing only the config part of the code below. I used Python for templating.
imports:
- path: ../network/vpc/vpc_network.py
name: vpc_network.py
- path: ../network/firewall/firewall_rule.py
name: firewall_rule.py
- path: ../compute/instance_template/instance_template.py
name: instance_template.py
- path: ../compute/health_checks/health_check.py
name: health_check.py
- path: ../compute/instance_group/mananged/instance_group.py
name: instance_group.py
- path: ../network_services/load_balancing/external_loadBalancers/external_load_balancer.py
name: external_load_balancer.py
resources:
- name: demo-firewall-rules-1
type: firewall_rule.py
properties:
rules:
- name: "allow-ssh-for-all"
description: "tcp firewall enable from all"
network: $(ref.net-10-69-16.network)
priority: 1000
action: "allow"
direction: "INGRESS"
sourceRanges: ['0.0.0.0/0']
ipProtocol: "tcp"
ipPorts: ["22"]
- name: "test-health-check-for-ig"
description: "enable health check to work on the project"
network: $(ref.net-10-69-16.network)
priority: 1000
action: "allow"
direction: "INGRESS"
sourceRanges: ['130.211.0.0/22', '35.191.0.0/16']
ipProtocol: "tcp"
ipPorts: ["80", "443"]
- name: "allow-http-https-from-anywhere"
description: "allow http and https from anywhere"
network: $(ref.net-10-69-16.network)
priority: 1000
action: "allow"
direction: "INGRESS"
sourceRanges: ['0.0.0.0/0']
ipProtocol: "tcp"
ipPorts: ["80", "443"]
- name: net-10-69-16
type: vpc_network.py
properties:
subnetworks:
- region: australia-southeast1
cidr: 10.69.10.0/24
- region: australia-southeast1
cidr: 10.69.20.0/24
- region: australia-southeast1
cidr: 10.69.30.0/24
- name: mig-regional-1
type: instance_group.py
properties:
region: australia-southeast1
instanceTemplate: $(ref.it-demo-1.selfLink)
targetSize: 2
autoHealingPolicies:
- healthCheck: $(ref.demo-http-healthcheck-MIG-1.selfLink)
initialDelaySec: 400
- name: it-demo-1
type: instance_template.py
properties:
machineType: n1-standard-1
tags:
items:
- http
disks:
- deviceName: boot-disk-v1
initializeParams:
sourceImage: projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20201211
diskType: pd-ssd
networkInterfaces:
- network: $(ref.net-10-69-16.network)
subnetwork: $(ref.net-10-69-16.subnetworks[0])
accessConfigs:
- type: ONE_TO_ONE_NAT
metadata:
items:
- key: startup-script
value: |
sudo apt-get install -y apache2
sudo apt-get install -y php7.0
sudo service apache2 restart
sudo echo "Ho Ho Ho from $HOSTNAME" > /var/www/html/index.html
- name: demo-http-healthcheck-MIG-1
type: health_check.py
properties:
type: HTTP
checkIntervalSec: 5
timeoutSec: 5
unhealthyThreshold: 2
healthyThreshold: 2
httpHealthCheck:
port: 80
requestPath: /
- name: http-elb-1
type: external_load_balancer.py
properties:
portRange: 80
backendServices:
- resourceName: backend-service-for-http-1
sessionAffinity: NONE
affinityCookieTtlSec: 1000
portName: http
healthCheck: $(ref.demo-http-healthcheck-MIG-1.selfLink)
backends:
- group: $(ref.mig-regional-1.selfLink)
balancingMode: UTILIZATION
maxUtilization: 0.8
urlMap:
defaultService: backend-service-for-http-1
The problem is with the load balancer. When it is present in the same file, the deployment fails saying the managed instance group mig-regional-1 does not exist. But when I move the load balancer part out of this file and deploy the load balancer separately, (after a bit of delay) it all goes through well.
The most probable explanation is, the instance group is not ready when the load balancer is trying to reference it which is the exact situation ref.*.selfLink is supposed to handle.
This is not exactly a blocker, but it is nice to have the entire config in 1 file.
So, my questions:
Have any of you faced this before or am I missing something here?
Do you have any solution for this?
Your template need to explicit its dependencies.
You can have dependencies between your resources, such as when you
need certain parts of your environment to exist before you can deploy
other parts of the environment.
You can specify dependencies using the dependsOn option in your templates.
Seems that your External LB needs dependsOn attribute that has MIG value.
refer here to get more information about expliciting dependencies.

Adding EKS managed windows node group failed. How to debug?

At AWS Console,
I created an AWS EKS Node IAM role with following IAM policies:
AmazonEKSWorkerNodePolicy
AmazonEKS_CNI_Policy
AmazonEC2ContainerRegistryReadOnly
I created launch template with the AMI, ami-0e6430de0e2d50a33
(Windows_Server-English-Full-EKS-Optimized-1.16-2020.09.09)
I have an existing eks cluster created by terraform (0.11.13). It has one eks node group. I would like to add a new windows eks node group manually. At AWS console, I went to my eks cluster, clicked on "Add Node Group", use the template above, and clicked on the "Create button". But, I got "Create failed". I have no clue cause of the failure. Where can I find the logs at AWS console?
Not sure where to find those type of logs.
However, here is an AWS CloudFormation template we use to create a self-managed Windows Server 2019 node group that joins the given cluster. Note that it uses spot instances and the worker nodes also join an existing AD.
You will need to either export your EKS cluster name from another CF template or hard-code the value in the UserData property (or pass in your EKS cluster name).
Remove the line 'New-SSMAssociation' line if not joining the AD.
AWSTemplateFormatVersion: 2010-09-09
Description: Creates EC2 instances to support the EKS cluster worker nodes.
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
-
Label:
default: "EKS Worker Nodes Configuration"
Parameters:
- Environment
- NodeImageIdSSMParam
- SpotPrice
- Subnets
- ActiveDirectoryIdentifier
- ActiveDirectoryName
- DesiredCapacity
- MaxCapacity
- MinCapacity
Parameters:
Environment:
Type: String
Description: The associated environment of the EKS cluster.
AllowedValues:
- preprod
- prod
BootstrapArguments:
Type: String
Default: ""
Description: Arguments to pass to the bootstrap script.
NodeImageIdSSMParam:
Type: "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>"
Default: /aws/service/ami-windows-latest/Windows_Server-2019-English-Core-EKS_Optimized-1.17/image_id
Description: AWS Systems Manager Parameter Store parameter of the AMI ID for the worker node instances.
SpotPrice:
Type: String
Description: The spot price to bid for the EKS Optimized instances.
Default: 0.4000
Subnets:
Description: Select the PRIVATE subnets where workers can be created.
Type: List<AWS::EC2::Subnet::Id>
ActiveDirectoryIdentifier:
Type: String
Description: The identifier of the shared Microsoft Managed AD
ActiveDirectoryName:
Type: String
Description: The name of the shared Microsoft Managed AD
DesiredCapacity:
Type: Number
Description: The desired number of EC2 instances for the Autoscaling group.
Default: 6
MaxCapacity:
Type: Number
Description: The maximum number of EC2 instances for the Autoscaling group.
Default: 6
MinCapacity:
Type: Number
Description: The minimum number of EC2 instances for the Autoscaling group.
Default: 6
Resources:
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
DeleteOnTermination: true
VolumeSize: 50
VolumeType: gp2
LaunchConfigurationName: !Sub eks-worker-nodes-windows-${Environment}-launch-config
SpotPrice: !Ref SpotPrice
AssociatePublicIpAddress: false
ImageId: !Ref NodeImageIdSSMParam
InstanceType: t3.large
IamInstanceProfile: !ImportValue eks-worker-instance-profile-arn
InstanceMonitoring: true
KeyName: samtec-ec2-key
SecurityGroups:
- Fn::ImportValue: !Sub eks-${Environment}-sg
UserData:
Fn::Base64: !Sub
- |
<powershell>
Set-DefaultAWSRegion -Region ${AWS::Region}
Set-Variable -name instance_id -value (Invoke-Restmethod -uri http://169.254.169.254/latest/meta-data/instance-id)
New-SSMAssociation -InstanceId $instance_id -Name "awsconfig_Domain_${ActiveDirectoryIdentifier}_${ActiveDirectoryName}"
[string]$EKSBinDir = "$env:ProgramFiles\Amazon\EKS"
[string]$EKSBootstrapScriptName = 'Start-EKSBootstrap.ps1'
[string]$EKSBootstrapScriptFile = "$EKSBinDir\$EKSBootstrapScriptName"
[string]$cfn_signal = "$env:ProgramFiles\Amazon\cfn-bootstrap\cfn-signal.exe"
& $EKSBootstrapScriptFile -EKSClusterName ${ClusterName} ${BootstrapArguments} 3>&1 4>&1 5>&1 6>&1
$LastError = if ($?) { 0 } else { $Error[0].Exception.HResult }
& $cfn_signal --exit-code=$LastError `
--stack="${AWS::StackName}" `
--resource="NodeGroup" `
--region=${AWS::Region}
</powershell>
- ClusterName:
'Fn::ImportValue': !Sub 'eks-${Environment}-name'
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub eks-worker-nodes-windows-${Environment}-autoscaler
Cooldown: 30
DesiredCapacity: !Ref DesiredCapacity
HealthCheckGracePeriod: 300
HealthCheckType: EC2
LaunchConfigurationName: !Ref LaunchConfiguration
MaxSize: !Ref MaxCapacity
MinSize: !Ref MinCapacity
MetricsCollection:
- Granularity: 1Minute
Tags:
- Key: Name
Value: !Sub eks-windows-${Environment}-worker
PropagateAtLaunch: true
- Key: operating-system
Value: windows
PropagateAtLaunch: true
- Key: !Sub
- |
kubernetes.io/cluster/${ClusterName}
- ClusterName:
'Fn::ImportValue': !Sub 'eks-${Environment}-name'
Value: owned
PropagateAtLaunch: true
- Key: !Sub
- |
k8s.io/cluster-autoscaler/${ClusterName}
- ClusterName:
'Fn::ImportValue': !Sub 'eks-${Environment}-name'
Value: owned
PropagateAtLaunch: true
- Key: k8s.io/cluster-autoscaler/enabled
Value: true
PropagateAtLaunch: true
- Key: eks:cluster-name
Value:
'Fn::ImportValue': !Sub 'eks-${Environment}-name'
PropagateAtLaunch: true
- Key: eks:nodegroup-name
Value:
'Fn::ImportValue': !Sub 'eks-${Environment}-name'
PropagateAtLaunch: true
VPCZoneIdentifier: !Ref Subnets

Configure a Firewall and a Startup Script with Deployment Manager

I'm carrying out the lab of the GCP platform "Configure a Firewall and a Startup Script with Deployment Manager", i changed the qwicklabs.jinja for this code:
resources:
- name: default-allow-http
type: compute.v1.firewall
properties:
targetTags: ["http"]
sourceRanges: ["0.0.0.0/0"]
allowed:
- IPProtocol: TCP
ports: ["80"]
- type: compute.v1.instance
name: vm-test
properties:
zone: {{ properties["zone"] }}
machineType: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/zones/{{ properties["zone"] }}/machineTypes/f1-micro
# For examples on how to use startup scripts on an instance, see:
# https://cloud.google.com/compute/docs/startupscript
tags:
items: ["http"]
metadata:
items:
- key: startup-script
value: "apt-get update \n apt-get install -y apache2"
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-{{ env["deployment"] }}
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-9
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/global/networks/default
# Access Config required to give the instance a public IP address
accessConfigs:
- name: External NAT
type: ONE_TO_ONE_NAT
The VM and Disk are made succesfully but i can't complete the last task "Check that Deployment manager includes startup script and firewall resource" because i have problems making the firewall rule an this appear:
ERROR: (gcloud.deployment-manager.deployments.create) Error in Operation [operation-1598852175371-5a
e25c7f61bda-1c55c951-22ca1242]: errors:
- code: RESOURCE_ERROR
location: /deployments/deployment-templates/resources/http-firewall-rule
message: '{"ResourceType":"compute.v1.firewall","ResourceErrorCode":"400","ResourceErrorMessage":{
"code":400,"message":"Request
contains an invalid argument.","status":"INVALID_ARGUMENT","statusMessage":"Bad
Request","requestPath":"https://compute.googleapis.com/compute/v1/projects/qwiklabs-gcp-01-888e7
df2843f/global/firewalls","httpMethod":"POST"}}'
Could someone help me pls? I have to finish this lab!
Your file was giving me for some reason "invalid format" error so I created a new Deployment Manager config file; took VM template from here, added your external IP configuration and also firewall rule part (without any changes).
My yaml file looks like this (I didn't use any variables though).
resources:
- name: vm-created-by-deployment-manager
type: compute.v1.instance
properties:
zone: us-central1-a
machineType: zones/us-central1-a/machineTypes/n1-standard-1
tags:
items: ["http"]
metadata:
items:
- key: startup-script
value: "apt-get update \n apt-get install -y apache2"
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
sourceImage: projects/debian-cloud/global/images/family/debian-9
networkInterfaces:
- network: global/networks/default
accessConfigs:
- name: External NAT
type: ONE_TO_ONE_NAT
- name: default-allow-http3
type: compute.v1.firewall
properties:
targetTags: ["http"]
sourceRanges: ["0.0.0.0/0"]
allowed:
- IPProtocol: TCP
ports: ["80"]
When I ran the file everything worked as intended:
wbogacz#cloudshell:~/fire (wojtek)$ gcloud deployment-manager deployments create test1 --config dm1.yaml
The fingerprint of the deployment is b'n63E-AtErTCKtWOvktfUsA=='
Waiting for create [operation-1599036146720-5ae5-----99-2a45880e-addbce89]...done.
Create operation operation-1599036146720-5ae-----99-2a45880e-addbce89 completed successfully.
NAME TYPE STATE ERRORS INTENT
default-allow-http3 compute.v1.firewall COMPLETED []
vm-created-by-deployment-manager compute.v1.instance COMPLETED []
At the end I logged in via SSH to the VM and verified that the startup script was executed - and again success.

Serverless Steps Functions: how to pass data from Lambda to ECS Fargate task

I am trying to configure a simple multi-step job using AWS Steps Functions with the Serverless Framework which involves as a first step a lambda generating json output and as a second step a Fargate Task which should receive the json as input.
Basically the lambda generates the following output:
{
'payload': 'Some payload as a string'
}
I need to pass this output as input to the Fargate task, as environment variable or any other method but I can't understand which syntax should I use. I've tried the following:
stepFunctions:
stateMachines:
MyStateMachine:
name: MyStateMachine
loggingConfig:
level: ALL
includeExecutionData: true
destinations:
- Fn::GetAtt: [StateMachineLogGroup, Arn]
definition:
StartAt: LambdaStep
States:
LambdaStep:
Type: Task
Resource:
Fn::GetAtt: [lambda_step, Arn]
ResultPath: $
Next: FargateStep
FargateStep:
Type: Task
Resource: arn:aws:states:::ecs:runTask.sync
Parameters:
Cluster: "#{ECSCluster}"
TaskDefinition: "#{FargateTaskDefinition}"
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- "#{PublicSubnetOne}"
- "#{PublicSubnetTwo}"
AssignPublicIp: ENABLED
Overrides:
ContainerOverrides:
- Name: my-fargate-container
Environment:
- Name: LAMBDA_RESULT
Value: $.payload
Next: Done
Done:
Type: Succeed
But in the container logs the environment variable LAMBDA_RESULT is simply set to $.payload meaning that the json path syntax is not resolved from the input.
I've also tried this
Overrides:
ContainerOverrides:
- Name: my-fargate-container
Environment:
- Name: LAMBDA_RESULT
Value: $$.payload
and this
FargateStep:
Type: Task
Resource: arn:aws:states:::ecs:runTask.sync
InputPath: $.payload # <-- added this
Parameters:
Cluster: "#{ECSCluster}"
TaskDefinition: "#{FargateTaskDefinition}"
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- "#{PublicSubnetOne}"
- "#{PublicSubnetTwo}"
AssignPublicIp: ENABLED
Overrides:
ContainerOverrides:
- Name: my-fargate-container
Environment:
- Name: LAMBDA_RESULT
Value: $.payload
Next: Done
No one worked. Any working example on how to properly pass data from Lambda to Fargate task using Step Functions?
I think the syntax should be:
ContainerOverrides:
- Name: my-fargate-container
Environment:
- Name: LAMBDA_RESULT
'Value.$': $.payload

How do I configure my PUBLIC AWS custom domain to resolve to a lambda that is configured for my VPC?

What is working:
Using the serverless framework:
I have configured an AWS VPC
I have an Amazon Aurora database configured
for my VPC
I have an AWS API Gateway lambda that is configured for my
VPC
When I deploy my lambda, I am able to access it publicly via the AWS
generated URL: XXX.execute-api.us-east-1.amazonaws.com/prod/outages
In my Lambda,I run a very simple query that proves I can connect to
my database.
This all works fine.
What is NOT working:
I have registered a domain with AWS/Route 53 and added a cert (e.g. *.foo.com)
I use the serverless-domain-manager plugin to make my lambda available via my domain (e.g. api.foo.com/outages resolves to XXX.execute-api.us-east-1.amazonaws.com/prod/outages)
This works fine if my lambda is NOT configured for my VPC
But when my lambda IS configured for my VPC, the custom domain api.foo.com/outages does NOT resolve to XXX.execute-api.us-east-1.amazonaws.com/prod/outages
I other words: I can NOT access api.foo.com/outages publicly.
What I need is:
1 - XXX.execute-api.us-east-1.amazonaws.com/prod/outages is available publicly (this works)
2 - My custom domain, api.foo.com/outages points to the SAME lambda as XXX.execute-api.us-east-1.amazonaws.com/prod/outages (in my VPC) and is available publicly (not working. I get: {"message":"Forbidden"})
virtual-private-cloud.yml
service: virtual-private-cloud
provider:
name: aws
region: us-east-1
stage: ${opt:stage, dev}
custom:
appVersion: 0.0.0
VPC_CIDR: 10
resources:
Resources:
ServerlessVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: ${self:custom.VPC_CIDR}.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
InstanceTenancy: default
ServerlessSubnetA:
DependsOn: ServerlessVPC
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: ServerlessVPC
AvailabilityZone: ${self:provider.region}a
CidrBlock: ${self:custom.VPC_CIDR}.0.0.0/24
ServerlessSubnetB:
DependsOn: ServerlessVPC
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: ServerlessVPC
AvailabilityZone: ${self:provider.region}b
CidrBlock: ${self:custom.VPC_CIDR}.0.1.0/24
ServerlessSubnetC:
DependsOn: ServerlessVPC
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: ServerlessVPC
AvailabilityZone: ${self:provider.region}c
CidrBlock: ${self:custom.VPC_CIDR}.0.2.0/24
Outputs:
VPCDefaultSecurityGroup:
Value:
Fn::GetAtt:
- ServerlessVPC
- DefaultSecurityGroup
Export:
Name: VPCDefaultSecurityGroup-${self:provider.stage}
SubnetA:
Description: 'Subnet A.'
Value: !Ref ServerlessSubnetA
Export:
Name: vpc-subnet-A-${self:provider.stage}
SubnetB:
Description: 'Subnet B.'
Value: !Ref ServerlessSubnetB
Export:
Name: vpc-subnet-B-${self:provider.stage}
SubnetC:
Description: 'Subnet C.'
Value: !Ref ServerlessSubnetC
Export:
Name: vpc-subnet-C-${self:provider.stage}
database-service.yml
service: database-service
provider:
name: aws
region: us-east-1
stage: ${opt:stage, dev}
environment:
stage: ${opt:stage, dev}
plugins:
- serverless-plugin-ifelse
custom:
appVersion: 0.0.1
AURORA:
DB_NAME: database${self:provider.stage}
USERNAME: ${ssm:/my-db-username~true}
PASSWORD: ${ssm:/my-db-password~true}
HOST:
Fn::GetAtt: [AuroraRDSCluster, Endpoint.Address]
PORT:
Fn::GetAtt: [AuroraRDSCluster, Endpoint.Port]
serverlessIfElse:
- If: '"${opt:stage}" == "prod"'
Set:
resources.Resources.AuroraRDSCluster.Properties.EngineMode: provisioned
ElseSet:
resources.Resources.AuroraRDSCluster.Properties.EngineMode: serverless
resources.Resources.AuroraRDSCluster.Properties.ScalingConfiguration.MinCapacity: 1
resources.Resources.AuroraRDSCluster.Properties.ScalingConfiguration.MaxCapacity: 4
ElseExclude:
- resources.Resources.AuroraRDSInstanceParameter
- resources.Resources.AuroraRDSInstance
resources:
Resources:
AuroraSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: "Aurora Subnet Group"
SubnetIds:
- 'Fn::ImportValue': vpc-subnet-A-${self:provider.stage}
- 'Fn::ImportValue': vpc-subnet-B-${self:provider.stage}
- 'Fn::ImportValue': vpc-subnet-C-${self:provider.stage}
AuroraRDSClusterParameter:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: Parameter group for the Serverless Aurora RDS DB.
Family: aurora5.6
Parameters:
character_set_database: "utf32"
AuroraRDSCluster:
Type: "AWS::RDS::DBCluster"
Properties:
MasterUsername: ${self:custom.AURORA.USERNAME}
MasterUserPassword: ${self:custom.AURORA.PASSWORD}
DBSubnetGroupName:
Ref: AuroraSubnetGroup
Engine: aurora
EngineVersion: "5.6.10a"
DatabaseName: ${self:custom.AURORA.DB_NAME}
BackupRetentionPeriod: 3
DBClusterParameterGroupName:
Ref: AuroraRDSClusterParameter
VpcSecurityGroupIds:
- 'Fn::ImportValue': VPCDefaultSecurityGroup-${self:provider.stage}
# this is needed for non-serverless mode
AuroraRDSInstanceParameter:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: Parameter group for the Serverless Aurora RDS DB.
Family: aurora5.6
Parameters:
sql_mode: IGNORE_SPACE
max_connections: 100
wait_timeout: 900
interactive_timeout: 900
# this is needed for non-serverless mode
AuroraRDSInstance:
Type: "AWS::RDS::DBInstance"
Properties:
DBInstanceClass: db.t2.small
DBSubnetGroupName:
Ref: AuroraSubnetGroup
Engine: aurora
EngineVersion: "5.6.10a"
PubliclyAccessible: false
DBParameterGroupName:
Ref: AuroraRDSInstanceParameter
DBClusterIdentifier:
Ref: AuroraRDSCluster
Outputs:
DatabaseName:
Description: 'Database name.'
Value: ${self:custom.AURORA.DB_NAME}
Export:
Name: DatabaseName-${self:provider.stage}
DatabaseHost:
Description: 'Database host.'
Value: ${self:custom.AURORA.HOST}
Export:
Name: DatabaseHost-${self:provider.stage}
DatabasePort:
Description: 'Database port.'
Value: ${self:custom.AURORA.PORT}
Export:
Name: DatabasePort-${self:provider.stage}
outage-service.yml
service: outage-service
package:
individually: true
plugins:
- serverless-bundle
- serverless-plugin-ifelse
- serverless-domain-manager
custom:
appVersion: 0.0.12
stage: ${opt:stage}
domains:
prod: api.foo.com
test: test-api.foo.com
dev: dev-api.foo.com
customDomain:
domainName: ${self:custom.domains.${opt:stage}}
stage: ${opt:stage}
basePath: outages
custom.customDomain.certificateName: "*.foo.com"
custom.customDomain.certificateArn: 'arn:aws:acm:us-east-1:395671985612:certificate/XXXX'
createRoute53Record: true
serverlessIfElse:
- If: '"${opt:stage}" == "prod"'
Set:
custom.customDomain.enabled: true
ElseSet:
custom.customDomain.enabled: false
provider:
name: aws
runtime: nodejs12.x
stage: ${opt:stage}
region: us-east-1
environment:
databaseName: !ImportValue DatabaseName-${self:provider.stage}
databaseUsername: ${ssm:/my-db-username~true}
databasePassword: ${ssm:/my-db-password~true}
databaseHost: !ImportValue DatabaseHost-${self:provider.stage}
databasePort: !ImportValue DatabasePort-${self:provider.stage}
functions:
hello:
memorySize: 2048
timeout: 30
handler: functions/handler.hello
vpc:
securityGroupIds:
- 'Fn::ImportValue': VPCDefaultSecurityGroup-${self:provider.stage}
subnetIds:
- 'Fn::ImportValue': vpc-subnet-A-${self:provider.stage}
- 'Fn::ImportValue': vpc-subnet-B-${self:provider.stage}
- 'Fn::ImportValue': vpc-subnet-C-${self:provider.stage}
environment:
functionName: getTowns
events:
- http:
path: outage
method: get
cors:
origin: '*'
headers:
- Content-Type
- authorization
resources:
- Outputs:
ApiGatewayRestApiId:
Value:
Ref: ApiGatewayRestApi
Export:
Name: ${self:custom.stage}-ApiGatewayRestApiId
ApiGatewayRestApiRootResourceId:
Value:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
Export:
Name: ${self:custom.stage}-ApiGatewayRestApiRootResourceId
I believe you might have missed to add VPC endpoints for API Gateway.
Ensure you create a VPC interface endpoint for API GW and use it in the API you create. This will allow API requests to lambda running within VPC
References:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-apis.html#apigateway-private-api-create-interface-vpc-endpoint
https://aws.amazon.com/blogs/compute/introducing-amazon-api-gateway-private-endpoints/
Hope this helps !!
SOLUTION: We found a solution, in our case the solution is that you can't use wildcard certificates. So if you make a certificate for the exact API URL it does work. Obviously this is not a nice solution for everyone and everything but when you do have this problem and must deploy you can make it work this way.
Also maybe good to mention we did not have any additional problems with the below mentioned case:
I also wanted to add a post I found that might also have lead to this setup not working even if we do get the network to play nice. But again if you or anyone has a working setup like the above mentioned one let me know how you did it.
TLDR
If anyone wants to understand what was going on with API Gateway, take
a look at this thread.
It basically says that API Gateway processes regular URLs (like
aaaaaaaaaaaa.execute-api.us-east-1.amazonaws.com) differently than how
it processes Custom Domain Name URLs (like api.myservice.com). So when
API Gateway forwards your API request to your Lambda Function, your
Lambda Function will receive different path values, depending on which
type of your URL you used to invoke your API.
source:
Understanding AWS API Gateway Custom Domain Names