diff --git a/blogs/ecs-service-connectivity/yelb/deployments/platformdeployment/AWS/ECS/mesh/yelb-appmesh-db.sh b/blogs/ecs-service-connectivity/yelb/deployments/platformdeployment/AWS/ECS/mesh/yelb-appmesh-db.sh index 0695d047..1b766537 100644 --- a/blogs/ecs-service-connectivity/yelb/deployments/platformdeployment/AWS/ECS/mesh/yelb-appmesh-db.sh +++ b/blogs/ecs-service-connectivity/yelb/deployments/platformdeployment/AWS/ECS/mesh/yelb-appmesh-db.sh @@ -1,3 +1,4 @@ + #Gets the yelb db endpoint from yelb-fargate cloudformation stack export YELB_DB_ENDPOINT=$(aws cloudformation describe-stacks --stack-name yelb-fargate --query "Stacks[0].Outputs[?OutputKey=='YelbDBEndpointUrl'].OutputValue" --output text) diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/cleanup.sh b/walkthroughs/eks-app-mesh-cross-account-acm/cleanup.sh new file mode 100755 index 00000000..36519f02 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/cleanup.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +set -e +export AWS_PAGER="" + +echo "Deleting the EKS clusters" +eksctl delete -p frontend cluster -f /tmp/eks-frontend-configuration.yml +eksctl delete -p backend cluster -f /tmp/eks-backend-configuration.yml + +echo "Deleting the App Mesh virtual services" +aws --profile frontend appmesh delete-virtual-service \ + --mesh-name am-multi-account-mesh \ + --virtual-service-name yelb-db + +aws --profile frontend appmesh delete-virtual-service \ + --mesh-name am-multi-account-mesh \ + --virtual-service-name redis-server + +aws --profile frontend appmesh delete-virtual-service \ + --mesh-name am-multi-account-mesh \ + --virtual-service-name yelb-appserver + +aws --profile frontend appmesh delete-virtual-service \ + --mesh-name am-multi-account-mesh \ + --virtual-service-name yelb-ui + +echo "Deleting the App Mesh virtual router" +aws --profile frontend appmesh delete-route \ + --mesh-name am-multi-account-mesh \ + --virtual-router-name yelb-appserver-virtual-router \ + --route-name route-to-yelb-appserver + +aws --profile frontend appmesh delete-virtual-router \ + --mesh-name am-multi-account-mesh \ + --virtual-router-name yelb-appserver-virtual-router + +echo "Deleting the App Mesh virtual nodes" +aws --profile frontend appmesh delete-virtual-node \ + --mesh-name am-multi-account-mesh \ + --virtual-node-name redis-server_yelb + +aws --profile frontend appmesh delete-virtual-node \ + --mesh-name am-multi-account-mesh \ + --virtual-node-name yelb-db_yelb + +aws --profile frontend appmesh delete-virtual-node \ + --mesh-name am-multi-account-mesh \ + --virtual-node-name yelb-appserver_yelb + +aws --profile frontend appmesh delete-virtual-node \ + --mesh-name am-multi-account-mesh \ + --virtual-node-name yelb-ui_yelb + +echo "Deleting the App Mesh mesh" +aws --profile frontend appmesh delete-mesh \ + --mesh-name am-multi-account-mesh + +echo "Deleting Cloud Map Services" +NAMESPACE=$(aws --profile backend servicediscovery list-namespaces | \ + jq -r ' .Namespaces[] | select ( .Properties.HttpProperties.HttpName == "am-multi-account.local" ) | .Id '); +SERVICE_ID=$(aws --profile backend servicediscovery list-services --filters Name="NAMESPACE_ID",Values=$NAMESPACE,Condition="EQ" | jq -r ' .Services[] | [ .Id ] | @tsv ' ) +aws --profile backend servicediscovery list-instances --service-id $SERVICE_ID | jq -r ' .Instances[] | [ .Id ] | @tsv ' |\ + while IFS=$'\t' read -r instanceId; do + aws --profile backend servicediscovery deregister-instance --service-id $SERVICE_ID --instance-id $instanceId + done +aws --profile backend servicediscovery list-services \ + --filters Name="NAMESPACE_ID",Values=$NAMESPACE,Condition="EQ" | \ +jq -r ' .Services[] | [ .Id ] | @tsv ' | \ + while IFS=$'\t' read -r serviceId; do + aws --profile backend servicediscovery delete-service \ + --id $serviceId + done + +echo "Deleting CloudFormation templates" +aws --profile backend cloudformation delete-stack \ + --stack-name am-multi-account-routes +aws --profile backend cloudformation wait stack-delete-complete \ + --stack-name am-multi-account-routes + +aws --profile backend cloudformation delete-stack \ + --stack-name am-multi-account-infra +aws --profile backend cloudformation wait stack-delete-complete \ + --stack-name am-multi-account-infra + +aws --profile frontend cloudformation delete-stack \ + --stack-name am-multi-account-shared-mesh +aws --profile frontend cloudformation wait stack-delete-complete \ + --stack-name am-multi-account-shared-mesh + +aws --profile frontend cloudformation delete-stack \ + --stack-name am-multi-account-routes +aws --profile frontend cloudformation wait stack-delete-complete \ + --stack-name am-multi-account-routes + +aws --profile frontend cloudformation delete-stack \ + --stack-name am-multi-account-infra +aws --profile frontend cloudformation wait stack-delete-complete \ + --stack-name am-multi-account-infra + +echo "Cleanup finished" \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/eks/setup.sh b/walkthroughs/eks-app-mesh-cross-account-acm/eks/setup.sh new file mode 100755 index 00000000..8e5df871 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/eks/setup.sh @@ -0,0 +1,112 @@ +#!/bin/bash + +set -e + +echo "Creating a ClusterConfig file for the Frontend cluster..." + +FRONTEND_AWS_REGION=$(aws --profile frontend configure get region); +FRONTEND_PRIVSUB1_ID=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PrivateSubnet1") | .Value'); +FRONTEND_PRIVSUB2_ID=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PrivateSubnet2") | .Value'); +FRONTEND_PUBSUB1_ID=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PublicSubnet1") | .Value'); +FRONTEND_PUBSUB2_ID=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PublicSubnet2") | .Value'); +FRONTEND_PRIVSUB1_AZ=$(aws --profile frontend ec2 describe-subnets --subnet-ids $FRONTEND_PRIVSUB1_ID | jq -r .Subnets[].AvailabilityZone); +FRONTEND_PRIVSUB2_AZ=$(aws --profile frontend ec2 describe-subnets --subnet-ids $FRONTEND_PRIVSUB2_ID | jq -r .Subnets[].AvailabilityZone); +FRONTEND_PUBSUB1_AZ=$(aws --profile frontend ec2 describe-subnets --subnet-ids $FRONTEND_PUBSUB1_ID | jq -r .Subnets[].AvailabilityZone); +FRONTEND_PUBSUB2_AZ=$(aws --profile frontend ec2 describe-subnets --subnet-ids $FRONTEND_PUBSUB2_ID | jq -r .Subnets[].AvailabilityZone); +FRONTEND_NODES_IAM_POLICY=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:NodesSDPolicy") | .Value'); + +cat > /tmp/eks-frontend-configuration.yml <<-EKS_FRONTEND_CONF + apiVersion: eksctl.io/v1alpha5 + kind: ClusterConfig + metadata: + name: am-multi-account-1 + region: $FRONTEND_AWS_REGION + version: "1.18" + vpc: + subnets: + private: + $FRONTEND_PRIVSUB1_AZ: { id: $FRONTEND_PRIVSUB1_ID } + $FRONTEND_PRIVSUB2_AZ: { id: $FRONTEND_PRIVSUB2_ID } + public: + $FRONTEND_PUBSUB1_AZ: { id: $FRONTEND_PUBSUB1_ID } + $FRONTEND_PUBSUB2_AZ: { id: $FRONTEND_PUBSUB2_ID } + nodeGroups: + - name: am-multi-account-1-ng + labels: { role: workers } + instanceType: t3.large + desiredCapacity: 3 + ssh: + allow: false + privateNetworking: true + iam: + attachPolicyARNs: + - $FRONTEND_NODES_IAM_POLICY + - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy + - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy + - arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess + - arn:aws:iam::aws:policy/AWSAppMeshFullAccess + withAddonPolicies: + xRay: true + cloudWatch: true + externalDNS: true +EKS_FRONTEND_CONF + +echo "Creating the Frontend EKS cluster..." +eksctl create -p frontend cluster -f /tmp/eks-frontend-configuration.yml + +echo "Creating a ClusterConfig file for the Backend cluster..." + +BACKEND_AWS_REGION=$(aws --profile backend configure get region); +BACKEND_PRIVSUB1_ID=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PrivateSubnet1") | .Value'); +BACKEND_PRIVSUB2_ID=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PrivateSubnet2") | .Value'); +BACKEND_PUBSUB1_ID=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PublicSubnet1") | .Value'); +BACKEND_PUBSUB2_ID=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:PublicSubnet2") | .Value'); +BACKEND_PRIVSUB1_AZ=$(aws --profile backend ec2 describe-subnets --subnet-ids $BACKEND_PRIVSUB1_ID | jq -r .Subnets[].AvailabilityZone); +BACKEND_PRIVSUB2_AZ=$(aws --profile backend ec2 describe-subnets --subnet-ids $BACKEND_PRIVSUB2_ID | jq -r .Subnets[].AvailabilityZone); +BACKEND_PUBSUB1_AZ=$(aws --profile backend ec2 describe-subnets --subnet-ids $BACKEND_PUBSUB1_ID | jq -r .Subnets[].AvailabilityZone); +BACKEND_PUBSUB2_AZ=$(aws --profile backend ec2 describe-subnets --subnet-ids $BACKEND_PUBSUB2_ID | jq -r .Subnets[].AvailabilityZone); +BACKEND_NODES_IAM_POLICY=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:NodesSDPolicy") | .Value'); +BACKEND_NODES_SECURITY_GROUP=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:NodesSecurityGroup") | .Value'); + +cat > /tmp/eks-backend-configuration.yml <<-EKS_BACKEND_CONF + apiVersion: eksctl.io/v1alpha5 + kind: ClusterConfig + metadata: + name: am-multi-account-2 + region: $BACKEND_AWS_REGION + version: "1.18" + vpc: + subnets: + private: + $BACKEND_PRIVSUB1_AZ: { id: $BACKEND_PRIVSUB1_ID } + $BACKEND_PRIVSUB2_AZ: { id: $BACKEND_PRIVSUB2_ID } + public: + $BACKEND_PUBSUB1_AZ: { id: $BACKEND_PUBSUB1_ID } + $BACKEND_PUBSUB2_AZ: { id: $BACKEND_PUBSUB2_ID } + nodeGroups: + - name: am-multi-account-2-ng + labels: { role: workers } + instanceType: t3.large + desiredCapacity: 3 + ssh: + allow: false + privateNetworking: true + securityGroups: + withShared: true + withLocal: true + attachIDs: ['$BACKEND_NODES_SECURITY_GROUP'] + iam: + attachPolicyARNs: + - $BACKEND_NODES_IAM_POLICY + - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy + - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy + - arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess + - arn:aws:iam::aws:policy/AWSAppMeshFullAccess + withAddonPolicies: + xRay: true + cloudWatch: true + externalDNS: true +EKS_BACKEND_CONF + +echo "Creating the Backend EKS cluster..." +eksctl create -p backend cluster -f /tmp/eks-backend-configuration.yml \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/backend_vpc_peering_routes.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/backend_vpc_peering_routes.yaml new file mode 100644 index 00000000..5a270f0b --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/backend_vpc_peering_routes.yaml @@ -0,0 +1,29 @@ +Parameters: + ProjectName: + Type: String + Description: Project name to link stacks + Default: am-multi-account + + PeerCIDR: + Type: String + Default: 10.192.0.0/16 + +Resources: + + PeerRoute1: + Type: AWS::EC2::Route + Properties: + RouteTableId: + Fn::ImportValue: !Sub '${ProjectName}:PrivateRouteTable1' + DestinationCidrBlock: !Ref PeerCIDR + VpcPeeringConnectionId: + Fn::ImportValue: !Sub '${ProjectName}:VPCPeeringConnectionId' + + PeerRoute2: + Type: AWS::EC2::Route + Properties: + RouteTableId: + Fn::ImportValue: !Sub '${ProjectName}:PrivateRouteTable2' + DestinationCidrBlock: !Ref PeerCIDR + VpcPeeringConnectionId: + Fn::ImportValue: !Sub '${ProjectName}:VPCPeeringConnectionId' \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/frontend_vpc_peering_routes.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/frontend_vpc_peering_routes.yaml new file mode 100644 index 00000000..be73fef2 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/frontend_vpc_peering_routes.yaml @@ -0,0 +1,30 @@ +Parameters: + ProjectName: + Type: String + Description: Project name to link stacks + Default: am-multi-account + + PeerCIDR: + Type: String + Default: 10.193.0.0/16 + + VPCPeeringConnectionId: + Type: String + +Resources: + + PeerRoute1: + Type: AWS::EC2::Route + Properties: + RouteTableId: + Fn::ImportValue: !Sub '${ProjectName}:PrivateRouteTable1' + DestinationCidrBlock: !Ref PeerCIDR + VpcPeeringConnectionId: !Ref VPCPeeringConnectionId + + PeerRoute2: + Type: AWS::EC2::Route + Properties: + RouteTableId: + Fn::ImportValue: !Sub '${ProjectName}:PrivateRouteTable2' + DestinationCidrBlock: !Ref PeerCIDR + VpcPeeringConnectionId: !Ref VPCPeeringConnectionId \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/infrastructure_backend.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/infrastructure_backend.yaml new file mode 100644 index 00000000..78f59418 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/infrastructure_backend.yaml @@ -0,0 +1,358 @@ +Parameters: + ProjectName: + Type: String + Description: Project name to link stacks + Default: am-multi-account + + VpcCIDR: + Description: Please enter the IP range (CIDR notation) for this VPC + Type: String + Default: 10.193.0.0/16 + + PublicSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone + Type: String + Default: 10.193.10.0/24 + + PublicSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone + Type: String + Default: 10.193.11.0/24 + + PrivateSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone + Type: String + Default: 10.193.20.0/24 + + PrivateSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone + Type: String + Default: 10.193.21.0/24 + + FrontendAccountId: + Type: String + + PeerVPCId: + Type: String + + PeerRoleArn: + Type: String + +Resources: + + VPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VpcCIDR + EnableDnsSupport: true + EnableDnsHostnames: true + Tags: + - Key: Name + Value: !Ref ProjectName + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Ref ProjectName + + InternetGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref InternetGateway + VpcId: !Ref VPC + + PublicSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref PublicSubnet1CIDR + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${ProjectName} Public Subnet (AZ1) + + PublicSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref PublicSubnet2CIDR + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${ProjectName} Public Subnet (AZ2) + + PrivateSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref PrivateSubnet1CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Subnet (AZ1) + + PrivateSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref PrivateSubnet2CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Subnet (AZ2) + + NatGateway1EIP: + Type: AWS::EC2::EIP + DependsOn: InternetGatewayAttachment + Properties: + Domain: vpc + + NatGateway2EIP: + Type: AWS::EC2::EIP + DependsOn: InternetGatewayAttachment + Properties: + Domain: vpc + + NatGateway1: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt NatGateway1EIP.AllocationId + SubnetId: !Ref PublicSubnet1 + + NatGateway2: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt NatGateway2EIP.AllocationId + SubnetId: !Ref PublicSubnet2 + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${ProjectName} Public Routes + + DefaultPublicRoute: + Type: AWS::EC2::Route + DependsOn: InternetGatewayAttachment + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + PublicSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnet1 + + PublicSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnet2 + + PrivateRouteTable1: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Routes (AZ1) + + DefaultPrivateRoute1: + Type: AWS::EC2::Route + Properties: + RouteTableId: !Ref PrivateRouteTable1 + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway1 + + PrivateSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PrivateRouteTable1 + SubnetId: !Ref PrivateSubnet1 + + PrivateRouteTable2: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Routes (AZ2) + + DefaultPrivateRoute2: + Type: AWS::EC2::Route + Properties: + RouteTableId: !Ref PrivateRouteTable2 + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway2 + + PrivateSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PrivateRouteTable2 + SubnetId: !Ref PrivateSubnet2 + + NodesSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Allow traffic from frontend EKS + GroupName: frontend-eks-rules + SecurityGroupIngress: + - IpProtocol: "-1" + CidrIp: "10.192.0.0/16" + VpcId: !Ref VPC + + VPCPeeringConnection: + Type: 'AWS::EC2::VPCPeeringConnection' + Properties: + VpcId: !Ref VPC + PeerVpcId: !Ref PeerVPCId + PeerOwnerId: !Ref FrontendAccountId + PeerRoleArn: !Ref PeerRoleArn + + NodesSDPolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: ['appmesh-preview:*'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:CreateService'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:DeleteService'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:GetService'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:GetInstance'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:RegisterInstance'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:DeregisterInstance'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:ListInstances'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:ListNamespaces'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:ListServices'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:GetOperation'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:GetInstancesHealthStatus'] + Resource: '*' + - Effect: Allow + Action: ['servicediscovery:UpdateInstanceCustomHealthStatus'] + Resource: '*' + - Effect: Allow + Action: ['route53:GetHealthCheck'] + Resource: '*' + - Effect: Allow + Action: ['route53:CreateHealthCheck'] + Resource: '*' + - Effect: Allow + Action: ['route53:UpdateHealthCheck'] + Resource: '*' + - Effect: Allow + Action: ['route53:ChangeResourceRecordSets'] + Resource: '*' + - Effect: Allow + Action: ['route53:DeleteHealthCheck'] + Resource: '*' + + AppServerServiceDiscoveryNamespace: + Type: AWS::ServiceDiscovery::HttpNamespace + Properties: + Name: !Sub '${ProjectName}.local' + +Outputs: + + VPC: + Description: A reference to the created VPC + Value: !Ref VPC + Export: + Name: !Sub '${ProjectName}:VPC' + + PublicSubnets: + Description: A list of the public subnets + Value: !Join [ ",", [ !Ref PublicSubnet1, !Ref PublicSubnet2 ]] + + PrivateSubnets: + Description: A list of the private subnets + Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]] + + PublicSubnet1: + Description: A reference to the public subnet in the 1st Availability Zone + Value: !Ref PublicSubnet1 + Export: + Name: !Sub '${ProjectName}:PublicSubnet1' + + PublicSubnet2: + Description: A reference to the public subnet in the 2nd Availability Zone + Value: !Ref PublicSubnet2 + Export: + Name: !Sub '${ProjectName}:PublicSubnet2' + + PrivateSubnet1: + Description: A reference to the private subnet in the 1st Availability Zone + Value: !Ref PrivateSubnet1 + Export: + Name: !Sub '${ProjectName}:PrivateSubnet1' + + PrivateSubnet2: + Description: A reference to the private subnet in the 2nd Availability Zone + Value: !Ref PrivateSubnet2 + Export: + Name: !Sub '${ProjectName}:PrivateSubnet2' + + PrivateRouteTable1: + Value: !Ref PrivateRouteTable1 + Export: + Name: !Sub '${ProjectName}:PrivateRouteTable1' + + PrivateRouteTable2: + Value: !Ref PrivateRouteTable2 + Export: + Name: !Sub '${ProjectName}:PrivateRouteTable2' + + VPCPeeringConnectionId: + Value: !Ref VPCPeeringConnection + Export: + Name: !Sub '${ProjectName}:VPCPeeringConnectionId' + + NodesSecurityGroup: + Value: !Ref NodesSecurityGroup + Export: + Name: !Sub '${ProjectName}:NodesSecurityGroup' + + NodesSDPolicy: + Description: IAM Policy that will be added to the EKS nodes + Value: !Ref NodesSDPolicy + Export: + Name: !Sub '${ProjectName}:NodesSDPolicy' + + AppServerServiceDiscoveryNamespace: + Description: A SDS namespace that will be used by appserver + Value: !Ref AppServerServiceDiscoveryNamespace + Export: + Name: !Sub '${ProjectName}:AppServerServiceDiscoveryNamespace' diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/infrastructure_frontend.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/infrastructure_frontend.yaml new file mode 100644 index 00000000..b93be933 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/infrastructure_frontend.yaml @@ -0,0 +1,293 @@ +Description: This template deploys a VPC, with a pair of public and private subnets spread + across two Availability Zones. It deploys an internet gateway, with a default + route on the public subnets. It deploys a pair of NAT gateways (one in each AZ), + and default routes for them in the private subnets. + +Parameters: + ProjectName: + Type: String + Description: Project name to link stacks + Default: am-multi-account + + VpcCIDR: + Description: Please enter the IP range (CIDR notation) for this VPC + Type: String + Default: 10.192.0.0/16 + + PublicSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone + Type: String + Default: 10.192.10.0/24 + + PublicSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone + Type: String + Default: 10.192.11.0/24 + + PrivateSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone + Type: String + Default: 10.192.20.0/24 + + PrivateSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone + Type: String + Default: 10.192.21.0/24 + + BackendAccountId: + Type: String + +Resources: + + VPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VpcCIDR + EnableDnsSupport: true + EnableDnsHostnames: true + Tags: + - Key: Name + Value: !Ref ProjectName + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Ref ProjectName + + InternetGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref InternetGateway + VpcId: !Ref VPC + + PublicSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref PublicSubnet1CIDR + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${ProjectName} Public Subnet (AZ1) + + PublicSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref PublicSubnet2CIDR + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${ProjectName} Public Subnet (AZ2) + + PrivateSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref PrivateSubnet1CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Subnet (AZ1) + + PrivateSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref PrivateSubnet2CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Subnet (AZ2) + + NatGateway1EIP: + Type: AWS::EC2::EIP + DependsOn: InternetGatewayAttachment + Properties: + Domain: vpc + + NatGateway2EIP: + Type: AWS::EC2::EIP + DependsOn: InternetGatewayAttachment + Properties: + Domain: vpc + + NatGateway1: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt NatGateway1EIP.AllocationId + SubnetId: !Ref PublicSubnet1 + + NatGateway2: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt NatGateway2EIP.AllocationId + SubnetId: !Ref PublicSubnet2 + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${ProjectName} Public Routes + + DefaultPublicRoute: + Type: AWS::EC2::Route + DependsOn: InternetGatewayAttachment + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + PublicSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnet1 + + PublicSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnet2 + + PrivateRouteTable1: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Routes (AZ1) + + DefaultPrivateRoute1: + Type: AWS::EC2::Route + Properties: + RouteTableId: !Ref PrivateRouteTable1 + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway1 + + PrivateSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PrivateRouteTable1 + SubnetId: !Ref PrivateSubnet1 + + PrivateRouteTable2: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${ProjectName} Private Routes (AZ2) + + DefaultPrivateRoute2: + Type: AWS::EC2::Route + Properties: + RouteTableId: !Ref PrivateRouteTable2 + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway2 + + PrivateSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PrivateRouteTable2 + SubnetId: !Ref PrivateSubnet2 + + NodesSDPolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: ['servicediscovery:UpdateInstanceCustomHealthStatus'] + Resource: '*' + + VPCPeerRole: + Type: 'AWS::IAM::Role' + Properties: + AssumeRolePolicyDocument: + Statement: + - Principal: + AWS: !Ref BackendAccountId + Action: + - 'sts:AssumeRole' + Effect: Allow + Path: / + Policies: + - PolicyName: root + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: 'ec2:AcceptVpcPeeringConnection' + Resource: '*' + +Outputs: + VPC: + Description: A reference to the created VPC + Value: !Ref VPC + Export: + Name: !Sub '${ProjectName}:VPC' + + PublicSubnets: + Description: A list of the public subnets + Value: !Join [ ",", [ !Ref PublicSubnet1, !Ref PublicSubnet2 ]] + + PrivateSubnets: + Description: A list of the private subnets + Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]] + + PublicSubnet1: + Description: A reference to the public subnet in the 1st Availability Zone + Value: !Ref PublicSubnet1 + Export: + Name: !Sub '${ProjectName}:PublicSubnet1' + + PublicSubnet2: + Description: A reference to the public subnet in the 2nd Availability Zone + Value: !Ref PublicSubnet2 + Export: + Name: !Sub '${ProjectName}:PublicSubnet2' + + PrivateSubnet1: + Description: A reference to the private subnet in the 1st Availability Zone + Value: !Ref PrivateSubnet1 + Export: + Name: !Sub '${ProjectName}:PrivateSubnet1' + + PrivateRouteTable1: + Value: !Ref PrivateRouteTable1 + Export: + Name: !Sub '${ProjectName}:PrivateRouteTable1' + + PrivateRouteTable2: + Value: !Ref PrivateRouteTable2 + Export: + Name: !Sub '${ProjectName}:PrivateRouteTable2' + + PrivateSubnet2: + Description: A reference to the private subnet in the 2nd Availability Zone + Value: !Ref PrivateSubnet2 + Export: + Name: !Sub '${ProjectName}:PrivateSubnet2' + + NodesSDPolicy: + Description: IAM Policy that will be added to the EKS nodes + Value: !Ref NodesSDPolicy + Export: + Name: !Sub '${ProjectName}:NodesSDPolicy' + + VPCPeerRole: + Value: !GetAtt + - VPCPeerRole + - Arn + Export: + Name: !Sub '${ProjectName}:VPCPeerRole' \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/setup.sh b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/setup.sh new file mode 100755 index 00000000..ec47b185 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/infrastructure/setup.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +set -e + +echo "Creating the Frontend Account VPC..." + +aws --profile frontend cloudformation deploy \ +--template-file infrastructure/infrastructure_frontend.yaml \ +--parameter-overrides \ +"BackendAccountId=$(aws --profile backend sts get-caller-identity | jq -r .Account)" \ +--stack-name am-multi-account-infra \ +--capabilities CAPABILITY_IAM + +echo "Creating the Backend Account VPC..." + +aws --profile backend cloudformation deploy \ +--template-file infrastructure/infrastructure_backend.yaml \ +--parameter-overrides \ +"FrontendAccountId=$(aws --profile frontend sts get-caller-identity | jq -r .Account)" \ +"PeerVPCId=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:VPC") | .Value')" \ +"PeerRoleArn=$(aws --profile frontend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:VPCPeerRole") | .Value')" \ +--stack-name am-multi-account-infra \ +--capabilities CAPABILITY_IAM + +echo "Creating the VPC peering routes..." + +aws --profile frontend cloudformation deploy \ +--template-file infrastructure/frontend_vpc_peering_routes.yaml \ +--parameter-overrides \ +"VPCPeeringConnectionId=$(aws --profile backend cloudformation list-exports | jq -r '.Exports[] | select(.Name=="am-multi-account:VPCPeeringConnectionId") | .Value')" \ +--stack-name am-multi-account-routes \ +--capabilities CAPABILITY_IAM + +aws --profile backend cloudformation deploy \ +--template-file infrastructure/backend_vpc_peering_routes.yaml \ +--stack-name am-multi-account-routes \ +--capabilities CAPABILITY_IAM + diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/Config b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/Config new file mode 100644 index 00000000..7b359f7e --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/Config @@ -0,0 +1,26 @@ +package.Appmeshtls_multiaccounts = { + interfaces = (1.0); + + # Use NoOpBuild. See https://w.amazon.com/index.php/BrazilBuildSystem/NoOpBuild + build-system = no-op; + build-tools = { + 1.0 = { + NoOpBuild = 1.0; + }; + }; + + # Use runtime-dependencies for when you want to bring in additional + # packages when deploying. + # Use dependencies instead if you intend for these dependencies to + # be exported to other packages that build against you. + dependencies = { + 1.0 = { + }; + }; + + runtime-dependencies = { + 1.0 = { + }; + }; + +}; diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/apply_tls_on_yelb_nodes.sh b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/apply_tls_on_yelb_nodes.sh new file mode 100755 index 00000000..872d0ef5 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/apply_tls_on_yelb_nodes.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +#CreateCA +export certificateAuthorityArn=$(aws acm-pca create-certificate-authority --certificate-authority-configuration file://ca_config.txt --revocation-configuration file://revoke_config.txt --certificate-authority-type "ROOT" --idempotency-token 98256344 --tags Key=Name,Value=MyAppMeshPCA --profile frontend |jq -r '.CertificateAuthorityArn' ) + +sleep 0.5 + +export csr1=$(aws acm-pca get-certificate-authority-csr --certificate-authority-arn $certificateAuthorityArn --profile frontend |jq '.Csr') + +echo $csr1 > ca.csr +awk '{gsub(/\\n/,"\n")}1' ca.csr > ca_csr.csr +sed -i 's/\"//g' ca_csr.csr + + + +export CertificateArn=$(aws acm-pca issue-certificate --certificate-authority-arn $certificateAuthorityArn --csr file://ca_csr.csr --signing-algorithm SHA256WITHRSA --template-arn arn:aws:acm-pca:::template/RootCACertificate/V1 --validity Value=10,Type="YEARS" --idempotency-token 1234 --profile frontend | jq -r '.CertificateArn' ) + + +certificate=$(aws acm-pca get-certificate --certificate-authority-arn $certificateAuthorityArn --certificate-arn $CertificateArn --profile frontend |jq '.Certificate') + +echo $certificate > certificate.cer +awk '{gsub(/\\n/,"\n")}1' certificate.cer > cert.cer +sed -i 's/\"//g' cert.cer +aws acm-pca import-certificate-authority-certificate --certificate-authority-arn $certificateAuthorityArn --certificate file://cert.cer --profile frontend + +aws acm-pca create-permission --certificate-authority-arn $certificateAuthorityArn --actions IssueCertificate GetCertificate ListPermissions --principal acm.amazonaws.com --profile frontend + +#RAMShareCA +export frontendaccount=$(aws sts get-caller-identity --profile frontend | jq -r .'Account') +export backendaccount=$(aws sts get-caller-identity --profile backend | jq -r .'Account') + +export resourceshareArn=$(aws ram create-resource-share --name Shared_Private_CA_MESH --resource-arn $certificateAuthorityArn --principals $backendaccount --profile frontend | jq -r '.resourceShare.resourceShareArn') + +sleep 1 + +export CA_RESOURCE_INVITE_ARN=$(aws --profile backend ram get-resource-share-invitations | jq -r '.resourceShareInvitations[]|select (.resourceShareArn=='\"$resourceshareArn\"')|.resourceShareInvitationArn') + +aws --profile backend ram accept-resource-share-invitation --resource-share-invitation-arn $CA_RESOURCE_INVITE_ARN + + +#UpdateVirtualNodes +export backend_certificate_arn=$(aws acm request-certificate --domain-name "*.example.com" --certificate-authority-arn $certificateAuthorityArn --query CertificateArn --output text --profile backend) +export frontend_certificate_arn=$(aws acm request-certificate --domain-name "*.example.com" --certificate-authority-arn $certificateAuthorityArn --query CertificateArn --output text --profile frontend) + + +export frontendworkerrole=$(eksctl get iamidentitymapping --profile frontend --cluster am-multi-account-1 -o json |jq -r '.[].rolearn |split("/")|.[1]') +export backendworkerrole=$(eksctl get iamidentitymapping --profile backend --cluster am-multi-account-2 -o json |jq -r '.[].rolearn |split("/")|.[1]') + +aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSCertificateManagerReadOnly --role-name $frontendworkerrole --profile frontend +aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSCertificateManagerPrivateCAReadOnly --role-name $frontendworkerrole --profile frontend +aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSAppMeshPreviewEnvoyAccess --role-name $frontendworkerrole --profile frontend + + +aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSCertificateManagerReadOnly --role-name $backendworkerrole --profile backend +aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSCertificateManagerPrivateCAReadOnly --role-name $backendworkerrole --profile backend +aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSAppMeshPreviewEnvoyAccess --role-name $backendworkerrole --profile backend + + + +sed -e "s%CERTIFICATE_ARN%"$backend_certificate_arn"%g" -e "s%CA_ARN%"$certificateAuthorityArn"%g" -e "s%FRONTEND_ACCOUNT%"$frontendaccount"%g" redis_update > redis_update.json +sed -e "s%CERTIFICATE_ARN%"$backend_certificate_arn"%g" -e "s%CA_ARN%"$certificateAuthorityArn"%g" -e "s%FRONTEND_ACCOUNT%"$frontendaccount"%g" appserver_update > appserver_update.json +sed -e "s%CERTIFICATE_ARN%"$backend_certificate_arn"%g" -e "s%CA_ARN%"$certificateAuthorityArn"%g" -e "s%FRONTEND_ACCOUNT%"$frontendaccount"%g" yelb_db_update > yelb_db_update.json +sed -e "s%FRONTEND_CERTIFICATE_ARN%"$frontend_certificate_arn"%g" -e "s%CA_ARN%"$certificateAuthorityArn"%g" -e "s%FRONTEND_ACCOUNT%"$frontendaccount"%g" yelb_ui_update > yelb_ui_update.json + + +kubectl apply -f mesh/redis_update.yaml +kubectl apply -f mesh/appserver_update.yaml +kubectl apply -f mesh/yelb_db_update.yaml +kubectl apply -f mesh/yelb_ui_update.yaml + + diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/appserver_update.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/appserver_update.yaml new file mode 100644 index 00000000..59aebf37 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/appserver_update.yaml @@ -0,0 +1,81 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: yelb-appserver + namespace: yelb +spec: + backendDefaults: + clientPolicy: + tls: + enforce: true, + validation: + trust: + acm: + certificateAuthorityArns: CA_ARN + podSelector: + matchLabels: + app: yelb-appserver + listeners: + - portMapping: + port: 4567 + protocol: http + - tls: + mode: STRICT + certificate: + acm: + certificateArn: + protocol: http + serviceDiscovery: + awsCloudMap: + namespaceName: am-multi-account.local + serviceName: yelb-appserver + backends: + - virtualService: + virtualServiceRef: + name: yelb-db + - virtualService: + virtualServiceRef: + name: redis-server +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: yelb + name: yelb-appserver +spec: + awsName: yelb-appserver-virtual-router + listeners: + - portMapping: + port: 4567 + protocol: http + routes: + - name: route-to-yelb-appserver + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: yelb-appserver + weight: 1 + retryPolicy: + maxRetries: 2 + perRetryTimeout: + unit: ms + value: 2000 + httpRetryEvents: + - server-error + - client-error + - gateway-error +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: yelb-appserver + namespace: yelb +spec: + awsName: yelb-appserver + provider: + virtualRouter: + virtualRouterRef: + name: yelb-appserver diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/ca_config.txt b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/ca_config.txt new file mode 100644 index 00000000..8da6573e --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/ca_config.txt @@ -0,0 +1,12 @@ +{ + "KeyAlgorithm":"RSA_2048", + "SigningAlgorithm":"SHA256WITHRSA", + "Subject":{ + "Country":"US", + "Organization":"Example Corp", + "OrganizationalUnit":"Sales", + "State":"WA", + "Locality":"Seattle", + "CommonName":"www.example.com" + } +} diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/create_mesh.sh b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/create_mesh.sh new file mode 100755 index 00000000..eece4d93 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/create_mesh.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +MESH_OWNER=$(aws --profile frontend sts get-caller-identity | jq -r .Account) + +cat > /tmp/app-mesh.yml <<-EKS_CONF + apiVersion: appmesh.k8s.aws/v1beta2 + kind: Mesh + metadata: + name: am-multi-account-mesh + spec: + meshOwner: "$MESH_OWNER" + namespaceSelector: + matchLabels: + mesh: am-multi-account-mesh +EKS_CONF + +kubectl apply -f /tmp/app-mesh.yml diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/redis_update.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/redis_update.yaml new file mode 100644 index 00000000..fdf91d69 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/redis_update.yaml @@ -0,0 +1,43 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: redis-server + namespace: yelb +spec: + backendDefaults: + clientPolicy: + tls: + enforce: true, + validation: + trust: + acm: + certificateAuthorityArns: CA_ARN + podSelector: + matchLabels: + app: redis-server + listeners: + - portMapping: + port: 6379 + protocol: tcp + - tls: + mode: STRICT + certificate: + acm: + certificateArn: + protocol: http + serviceDiscovery: + dns: + hostname: redis-server.yelb.svc.cluster.local + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: redis-server + namespace: yelb +spec: + awsName: redis-server + provider: + virtualNode: + virtualNodeRef: + name: redis-server diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/revoke_config.txt b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/revoke_config.txt new file mode 100644 index 00000000..3c7f664e --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/revoke_config.txt @@ -0,0 +1,8 @@ +{ + "CrlConfiguration":{ + "Enabled":false, + "ExpirationInDays":7, + "CustomCname":"some_name.crl", + "S3BucketName":"your-bucket-name" + } +} diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-appserver.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-appserver.yaml new file mode 100644 index 00000000..766c54b8 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-appserver.yaml @@ -0,0 +1,67 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: yelb-appserver + namespace: yelb +spec: + podSelector: + matchLabels: + app: yelb-appserver + listeners: + - portMapping: + port: 4567 + protocol: http + serviceDiscovery: + awsCloudMap: + namespaceName: am-multi-account.local + serviceName: yelb-appserver + backends: + - virtualService: + virtualServiceRef: + name: yelb-db + - virtualService: + virtualServiceRef: + name: redis-server +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: yelb + name: yelb-appserver +spec: + awsName: yelb-appserver-virtual-router + listeners: + - portMapping: + port: 4567 + protocol: http + routes: + - name: route-to-yelb-appserver + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: yelb-appserver + weight: 1 + retryPolicy: + maxRetries: 2 + perRetryTimeout: + unit: ms + value: 2000 + httpRetryEvents: + - server-error + - client-error + - gateway-error +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: yelb-appserver + namespace: yelb +spec: + awsName: yelb-appserver + provider: + virtualRouter: + virtualRouterRef: + name: yelb-appserver \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-db.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-db.yaml new file mode 100644 index 00000000..ee1e4192 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-db.yaml @@ -0,0 +1,28 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: yelb-db + namespace: yelb +spec: + podSelector: + matchLabels: + app: yelb-db + listeners: + - portMapping: + port: 5432 + protocol: tcp + serviceDiscovery: + dns: + hostname: yelb-db.yelb.svc.cluster.local +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: yelb-db + namespace: yelb +spec: + awsName: yelb-db + provider: + virtualNode: + virtualNodeRef: + name: yelb-db \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-redis.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-redis.yaml new file mode 100644 index 00000000..f96fcce0 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-redis.yaml @@ -0,0 +1,28 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: redis-server + namespace: yelb +spec: + podSelector: + matchLabels: + app: redis-server + listeners: + - portMapping: + port: 6379 + protocol: tcp + serviceDiscovery: + dns: + hostname: redis-server.yelb.svc.cluster.local +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: redis-server + namespace: yelb +spec: + awsName: redis-server + provider: + virtualNode: + virtualNodeRef: + name: redis-server diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-ui.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-ui.yaml new file mode 100644 index 00000000..74e4c922 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb-ui.yaml @@ -0,0 +1,32 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: yelb-ui + namespace: yelb +spec: + podSelector: + matchLabels: + app: yelb-ui + listeners: + - portMapping: + port: 4567 + protocol: http + serviceDiscovery: + dns: + hostname: yelb-ui.yelb.svc.cluster.local + backends: + - virtualService: + virtualServiceARN: + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: yelb-ui + namespace: yelb +spec: + awsName: yelb-ui + provider: + virtualNode: + virtualNodeRef: + name: yelb-ui \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb_db_update.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb_db_update.yaml new file mode 100644 index 00000000..670e7ede --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb_db_update.yaml @@ -0,0 +1,43 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: yelb-db + namespace: yelb +spec: + backendDefaults: + clientPolicy: + tls: + enforce: true, + validation: + trust: + acm: + certificateAuthorityArns: CA_ARN + podSelector: + matchLabels: + app: yelb-db + listeners: + - portMapping: + port: 5432 + protocol: tcp + - tls: + mode: STRICT + certificate: + acm: + certificateArn: + protocol: http + serviceDiscovery: + dns: + hostname: yelb-db.yelb.svc.cluster.local + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: yelb-db + namespace: yelb +spec: + awsName: yelb-db + provider: + virtualNode: + virtualNodeRef: + name: yelb-db diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb_ui_update.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb_ui_update.yaml new file mode 100644 index 00000000..df767670 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/mesh/yelb_ui_update.yaml @@ -0,0 +1,46 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: yelb-ui + namespace: yelb +spec: + backendDefaults: + clientPolicy: + tls: + enforce: true, + validation: + trust: + acm: + certificateAuthorityArns: CA_ARN + podSelector: + matchLabels: + app: yelb-ui + listeners: + - portMapping: + port: 4567 + protocol: http + - tls: + mode: STRICT + certificate: + acm: + certificateArn: + protocol: http + serviceDiscovery: + dns: + hostname: yelb-ui.yelb.svc.cluster.local + backends: + - virtualService: + virtualServiceARN: + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: yelb-ui + namespace: yelb +spec: + awsName: yelb-ui + provider: + virtualNode: + virtualNodeRef: + name: yelb-ui diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/readme.md b/walkthroughs/eks-app-mesh-cross-account-acm/readme.md new file mode 100644 index 00000000..7f5a0b1f --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/readme.md @@ -0,0 +1,155 @@ +## Configure Frontend and Backend Account Profiles + +``` +cat ~/.aws/credentials + +[frontend] +aws_access_key_id = ... +aws_secret_access_key = ... +[backend] +aws_access_key_id = ... +aws_secret_access_key = ... + +cat ~/.aws/config + +[profile frontend] +region = us-west-2 +[profile backend] +region = us-west-2 +``` + +## Deploy the + +``` +./infrastructure/setup.sh +``` + +## Deploy EKS + +``` +./eks/setup.sh +``` + +## Deploy the App Mesh Controller on our Frontend Cluster + +``` +kubectl config use-context @am-multi-account-1..eksctl.io +``` + +``` +helm repo add eks https://aws.github.io/eks-charts +``` + +``` +kubectl create ns appmesh-system +helm upgrade -i appmesh-controller eks/appmesh-controller \ +--namespace appmesh-system + +kubectl -n appmesh-system get pods +``` + +## Deploy and Share Mesh + +``` +kubectl create ns yelb +kubectl label namespace yelb mesh=am-multi-account-mesh +kubectl label namespace yelb "appmesh.k8s.aws/sidecarInjectorWebhook"=enabled +``` + +``` +./mesh/create_mesh.sh +``` + +``` +aws --profile frontend cloudformation deploy \ +--template-file shared_resources/shared_mesh.yaml \ +--parameter-overrides \ +"BackendAccountId=$(aws --profile backend sts get-caller-identity | jq -r .Account)" \ +--stack-name am-multi-account-shared-mesh \ +--capabilities CAPABILITY_IAM +``` + +## Accept the invitation + +``` +aws --profile backend ram get-resource-share-invitations + +aws --profile backend ram accept-resource-share-invitation \ +--resource-share-invitation-arn +``` + +## Deploy the App Mesh Controller on our Backend Cluster + +``` +kubectl config use-context .eksctl.io +``` + +``` +helm repo add eks https://aws.github.io/eks-charts +``` + +``` +kubectl create ns appmesh-system +helm upgrade -i appmesh-controller eks/appmesh-controller \ +--namespace appmesh-system + +kubectl -n appmesh-system get pods +``` + +## Create the App Mesh Service Role on our Backend Account + +``` +aws --profile backend iam create-service-linked-role --aws-service-name appmesh.amazonaws.com +``` + +## Deploy Mesh Resources on our Backend Cluster + +``` +kubectl create ns yelb + +kubectl label namespace yelb mesh=am-multi-account-mesh +kubectl label namespace yelb "appmesh.k8s.aws/sidecarInjectorWebhook"=enabled +``` + +``` +./mesh/create_mesh.sh + +kubectl apply -f mesh/yelb-redis.yaml +kubectl apply -f mesh/yelb-db.yaml +kubectl apply -f mesh/yelb-appserver.yaml +``` + +## Deploy Yelb Resources on our Backend Cluster + +``` +kubectl apply -f yelb/resources_backend.yaml +``` + +## Deploy Mesh Resources on our Primary Cluster + +``` +kubectl config use-context @am-multi-account-1..eksctl.io +``` + +**Get the ```yelb-appserver``` VirtualService ARN value using below command and update ```mesh/yelb-ui.yaml``` accordingly**. + +``` +kubectl --context=@am-multi-account-2..eksctl.io \ +-n yelb get virtualservice yelb-appserver +``` + +``` +kubectl apply -f mesh/yelb-ui.yaml +``` + +## Deploy Yelb Resources on our Frontend Cluster + +``` +kubectl apply -f yelb/resources_frontend.yaml +``` + +## Cleanup + +``` +./cleanup.sh +``` diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/shared_resources/shared_mesh.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/shared_resources/shared_mesh.yaml new file mode 100644 index 00000000..dc0d304c --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/shared_resources/shared_mesh.yaml @@ -0,0 +1,19 @@ +Parameters: + ProjectName: + Type: String + Description: Project name to link stacks + Default: am-multi-account + BackendAccountId: + Type: String + Description: Account Id to share resources with + +Resources: + MeshShare: + Type: AWS::RAM::ResourceShare + Properties: + AllowExternalPrincipals: true + Name: mesh-share + Principals: + - !Ref BackendAccountId + ResourceArns: + - !Sub 'arn:aws:appmesh:${AWS::Region}:${AWS::AccountId}:mesh/${ProjectName}-mesh' \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/yelb/resources_backend.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/yelb/resources_backend.yaml new file mode 100644 index 00000000..e6b49758 --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/yelb/resources_backend.yaml @@ -0,0 +1,100 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: yelb + name: redis-server + labels: + app: redis-server + tier: cache +spec: + type: ClusterIP + ports: + - port: 6379 + selector: + app: redis-server + tier: cache +--- +apiVersion: v1 +kind: Service +metadata: + namespace: yelb + name: yelb-db + labels: + app: yelb-db + tier: backenddb +spec: + type: ClusterIP + ports: + - port: 5432 + selector: + app: yelb-db + tier: backenddb +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: yelb + name: redis-server +spec: + selector: + matchLabels: + app: redis-server + tier: cache + replicas: 1 + template: + metadata: + labels: + app: redis-server + tier: cache + spec: + containers: + - name: redis-server + image: redis:4.0.2 + ports: + - containerPort: 6379 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: yelb + name: yelb-db +spec: + replicas: 1 + selector: + matchLabels: + app: yelb-db + tier: backenddb + template: + metadata: + labels: + app: yelb-db + tier: backenddb + spec: + containers: + - name: yelb-db + image: mreferre/yelb-db:0.5 + ports: + - containerPort: 5432 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: yelb + name: yelb-appserver +spec: + replicas: 1 + selector: + matchLabels: + app: yelb-appserver + tier: middletier + template: + metadata: + labels: + app: yelb-appserver + tier: middletier + spec: + containers: + - name: yelb-appserver + image: mreferre/yelb-appserver:0.5 + ports: + - containerPort: 4567 \ No newline at end of file diff --git a/walkthroughs/eks-app-mesh-cross-account-acm/yelb/resources_frontend.yaml b/walkthroughs/eks-app-mesh-cross-account-acm/yelb/resources_frontend.yaml new file mode 100644 index 00000000..bae0423a --- /dev/null +++ b/walkthroughs/eks-app-mesh-cross-account-acm/yelb/resources_frontend.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: yelb + name: yelb-ui + labels: + app: yelb-ui + tier: frontend +spec: + type: LoadBalancer + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: yelb-ui + tier: frontend +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: yelb + name: yelb-ui +spec: + replicas: 1 + selector: + matchLabels: + app: yelb-ui + tier: frontend + template: + metadata: + labels: + app: yelb-ui + tier: frontend + spec: + containers: + - name: yelb-ui + image: mreferre/yelb-ui:0.6 + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + namespace: yelb + name: yelb-appserver +spec: + type: ClusterIP + ports: + - port: 4567 \ No newline at end of file diff --git a/walkthroughs/howto-cross-account/README.md b/walkthroughs/howto-cross-account/README.md index fa98aebb..5144d498 100644 --- a/walkthroughs/howto-cross-account/README.md +++ b/walkthroughs/howto-cross-account/README.md @@ -30,7 +30,7 @@ These backends will be configured in distinct accounts and made accessible throu 1. **Project Name** used to isolate resources created in this demo from other's in your account. e.g. howto-cross-account ``` - export PROJECT_NAME=howto-cross-account + export PROJECT_NAME=cross-account ``` 2. **Account IDs**: This demo needs two accounts to which are in the same AWS Organization. diff --git a/walkthroughs/howto-cross-account/primary-account/mesh.yaml b/walkthroughs/howto-cross-account/primary-account/mesh.yaml index cd60ba6b..a619b43e 100644 --- a/walkthroughs/howto-cross-account/primary-account/mesh.yaml +++ b/walkthroughs/howto-cross-account/primary-account/mesh.yaml @@ -35,6 +35,7 @@ Resources: Prefix: / VirtualGatewayName: !GetAtt VirtualGateway.VirtualGatewayName + BackendNode: Type: AWS::AppMesh::VirtualNode Properties: