--- AWSTemplateFormatVersion: 2010-09-09 Description: >- (qs-1qup6ra90) HashiCorp Vault License: Apache 2.0 (Please do not remove) Metadata: AWSAMIRegionMap: Filters: CISUBUNTU2004: product-code: 8wt6moitlqquyt3sdfbsorz2d QuickStartDocumentation: EntrypointName: Launch into an existing VPC Order: 2 LintSpellExclude: - Kubernetes - namespace - HashiCorp - Vault - balancer - vault-ui - Auto Scaling - Hosted - Domain - Unseal - unseal - Linux - xxxxxxxx - ACMSSLCertificateArn - DomainName - Amazon Resource Name - HostedZoneID - Name - Region - bucket - Bucket # QSLint: # Exclusions: [W9002, W9003, W9004, W9006] AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network configuration Parameters: - AccessCIDR - VPCID - VPCCIDR - BastionSecurityGroupID - PrivateSubnet1ID - PrivateSubnet2ID - PrivateSubnet3ID - PublicSubnet1ID - PublicSubnet2ID - PublicSubnet3ID - Label: default: Vault setup Parameters: - KeyPairName - VaultVersion - VaultAMIOS - VaultServerNodes - VaultInstanceType - VaultNumberOfKeys - VaultNumberOfKeysForUnseal - VaultClientRoleName - VaultClientNodes - VaultKubernetesEnable - VaultKubernetesHostURL - VaultKubernetesRoleName - VaultKubernetesCertificate - VaultKubernetesJWT - VaultKubernetesServiceAccount - VaultKubernetesNameSpace - VaultKubernetesPolicies - Label: default: AWS Quick Start configuration Parameters: - QSS3BucketName - QSS3KeyPrefix - QSS3BucketRegion - Label: default: Load balancer configuration Parameters: - LoadBalancerType - DomainName - HostedZoneID - ACMSSLCertificateArn ParameterLabels: BastionSecurityGroupID: default: Bastion host security group ID PrivateSubnet1ID: default: First subnet ID for Auto Scaling group PrivateSubnet2ID: default: Second subnet ID for Auto Scaling group PrivateSubnet3ID: default: Third subnet ID for Auto Scaling group PublicSubnet1ID: default: First public subnet ID for Auto Scaling group PublicSubnet2ID: default: Second public subnet ID for Auto Scaling group PublicSubnet3ID: default: Third public subnet ID for Auto Scaling group KeyPairName: default: EC2 key pair QSS3BucketName: default: Quick Start S3 bucket name QSS3KeyPrefix: default: Quick Start S3 object key prefix QSS3BucketRegion: default: Quick Start S3 bucket Region AccessCIDR: default: Permitted IP range VPCID: default: VPC ID VPCCIDR: default: VPC CIDR VaultVersion: default: HashiCorp Vault version VaultAMIOS: default: Vault cluster operating system VaultClientNodes: default: Vault client nodes VaultServerNodes: default: Vault server nodes VaultInstanceType: default: Instance type VaultNumberOfKeys: default: Unseal keys to create VaultNumberOfKeysForUnseal: default: Required unseal keys VaultClientRoleName: default: Vault AWS role name LoadBalancerType: default: Internal/external load balancer? ACMSSLCertificateArn: default: SSL certificate ARN HostedZoneID: default: Hosted-zone ID DomainName: default: Load balancer DNS domain name VaultKubernetesEnable: default: Enable Kubernetes authentication VaultKubernetesRoleName: default: Kubernetes Vault role name VaultKubernetesHostURL: default: Kubernetes host URL VaultKubernetesCertificate: default: Kubernetes CA certificate VaultKubernetesJWT: default: Kubernetes JWT token VaultKubernetesServiceAccount: default: Kubernetes service account name VaultKubernetesNameSpace: default: Kubernetes name space VaultKubernetesPolicies: default: Kubernetes Vault policies Parameters: VaultAMIOS: AllowedValues: - Ubuntu-2004-HVM - CIS-Ubuntu-2004-HVM Default: Ubuntu-2004-HVM Description: Linux distribution AMI for the Vault instances. Type: String KeyPairName: Description: Key pair to securely connect to your instance. Type: AWS::EC2::KeyPair::KeyName Default: id_rsa_aws ConstraintDescription: Must be the name of an existing EC2 KeyPair. BastionSecurityGroupID: Description: ID of the bastion host security group to enable SSH connections (e.g., sg-7f16e910). Type: AWS::EC2::SecurityGroup::Id VaultServerNodes: Type: String Description: Sets DesiredCapacity and MaxSize for Vault server Auto Scaling group. Default: 5 AllowedValues: - 3 - 5 - 7 VaultClientNodes: Type: String Description: Sets DesiredCapacity and MaxSize for Vault client Auto Scaling group. Default: 0 AllowedValues: - 0 - 1 VaultNumberOfKeys: Type: String Default: 5 AllowedPattern: ^([1-9]|[1-8][0-9]|9[0-9])$ ConstraintDescription: Must be a value between 1 and 99. Description: Number of un seal keys to create for HashiCorp Vault. VaultNumberOfKeysForUnseal: Type: String Default: 3 AllowedPattern: ^([1-9]|[1-8][0-9]|9[0-9])$ ConstraintDescription: Must be a value between 1 and 99. Description: Number of keys required to unseal HashiCorp Vault. VaultInstanceType: Type: String Description: HashiCorp Vault node instance type. AllowedValues: - c5.12xlarge - c5.18xlarge - c5.24xlarge - c5.2xlarge - c5.4xlarge - c5.9xlarge - c5.large - c5.xlarge - m5.12xlarge - m5.16xlarge - m5.24xlarge - m5.2xlarge - m5.4xlarge - m5.8xlarge - m5.large - m5.metal - m5.xlarge - r5.12xlarge - r5.16xlarge - r5.24xlarge - r5.2xlarge - r5.4xlarge - r5.8xlarge - r5.large - r5.xlarge - t3.2xlarge - t3.large - t3.medium - t3.micro - t3.nano - t3.small - t3.xlarge ConstraintDescription: Choose an instance type. m5.large or larger recommended. Default: m5.large QSS3BucketName: AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ ConstraintDescription: Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: S3 bucket name for the Quick Start assets. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String QSS3BucketRegion: Default: us-east-1 Description: AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value. Type: String QSS3KeyPrefix: AllowedPattern: ^[0-9a-zA-Z-/]*$ ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Default: quickstart-hashicorp-vault/ Description: S3 key prefix for the Quick Start assets. Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Type: String PrivateSubnet1ID: Description: ID of private subnet 1 in Availability Zone 1 (e.g., subnet-xxxxxxxx). Type: AWS::EC2::Subnet::Id PrivateSubnet2ID: Description: ID of private subnet 2 in Availability Zone 2 (e.g., subnet-xxxxxxxx). Type: AWS::EC2::Subnet::Id PrivateSubnet3ID: Description: ID of private subnet 3 in Availability Zone 3 (e.g., subnet-xxxxxxxx). Type: AWS::EC2::Subnet::Id PublicSubnet1ID: Description: ID of public subnet 1 in Availability Zone 1 (e.g., subnet-xxxxxxxx). Type: AWS::EC2::Subnet::Id PublicSubnet2ID: Description: ID of public subnet 2 in Availability Zone 2 (e.g., subnet-xxxxxxxx). Type: AWS::EC2::Subnet::Id PublicSubnet3ID: Description: ID of public subnet 3 in Availability Zone 3 (e.g., subnet-xxxxxxxx). Type: AWS::EC2::Subnet::Id AccessCIDR: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ Description: >- The CIDR IP range that is permitted to access Vault. Note: A value of 0.0.0.0/0 allows access from ANY IP address. Type: String VPCID: Description: VPC ID. Type: AWS::EC2::VPC::Id VPCCIDR: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ Description: CIDR block for the VPC. Type: String VaultVersion: Type: String Description: Specify which version of HashiCorp Vault to install. Default: 1.10.3 AllowedValues: - 1.5.5 - 1.6.1 - 1.10.3 VaultClientRoleName: Type: String Default: quickstart-client-role-iam MinLength: 3 ConstraintDescription: This identifier should be at least 3 characters in length. Description: The HashiCorp Vault name for the AWS IAM role. LoadBalancerType: Type: String Default: Internal Description: Specify if the load balancer for HashiCorp Vault is internal or external. AllowedValues: - Internal - External DomainName: Type: String Description: >- Fully qualified domain name for the HashiCorp Vault load balancer. If you don't provide a value for ACMSSLCertificateArn, use the HostedZoneID. MaxLength: 128 Default: '' HostedZoneID: Type: String Description: Route 53-hosted zone ID of the domain name. If you don't provide an ACMSSLCertificateArn value, the Quick Start creates the ACM certificate for you using HostedZoneID in conjunction with DomainName. Default: '' ACMSSLCertificateArn: Description: Amazon Resource Name (ARN) of the load balancer's SSL certificate. If you don't provide values for DomainName and HostedZoneID, provide a value for ACMSSLCertificateArn. Type: String Default: '' VaultKubernetesEnable: Description: Enable Kubernetes authentication and create Kubernetes authentication role. Type: String Default: 'false' AllowedValues: - 'true' - 'false' VaultKubernetesRoleName: Description: Internal Vault name for the Kubernetes authentication role. Type: String Default: kube-auth-role VaultKubernetesHostURL: Description: >- URL of Kubernetes cluster eg: https://192.168.99.100:8443. Type: String VaultKubernetesCertificate: Description: >- AWS SSM parameter containing a base64-encoded PEM CA certificate of the Kubernetes cluster service account. Default: '' Type: String VaultKubernetesJWT: Description: AWS SSM secure parameter containing a base64-encoded JWT token of the Kubernetes cluster service account. Default: '' Type: String VaultKubernetesServiceAccount: Description: Name of Kubernetes service account. Default: vault-auth Type: String VaultKubernetesNameSpace: Description: Vault namespace of the Kubernetes service account. Default: default Type: String VaultKubernetesPolicies: Description: Vault policies for the Kubernetes service account. Default: default Type: String Mappings: LinuxAMINameMap: Ubuntu-2004-HVM: Code: US2004HVM CIS-Ubuntu-2004-HVM: Code: CISUBUNTU2004 AWSAMIRegionMap: AMI: CISUBUNTU2004: CIS 1 Ubuntu 20.04 US2004HVM: Ubuntu 20.04 LTS eu-north-1: CISUBUNTU2004: ami-057614a40c691ad25 US2004HVM: ami-0ac289f307b3e90d1 ap-south-1: CISUBUNTU2004: ami-0812d50039dc44803 US2004HVM: ami-089fdf62e986e93ea eu-west-3: CISUBUNTU2004: ami-0c3991c399720ce4e US2004HVM: ami-04c512eb02ad15697 eu-west-2: CISUBUNTU2004: ami-0a0aef4eddab42e03 US2004HVM: ami-0c109f697ab7fc6f4 eu-west-1: CISUBUNTU2004: ami-066a2b721a2c8baea US2004HVM: ami-020fc399c31009b50 ap-northeast-2: CISUBUNTU2004: ami-020f35e96daeeb0dd US2004HVM: ami-0a0ac042031ba59d1 ap-northeast-1: CISUBUNTU2004: ami-0b8ceb50bcc3f1a32 US2004HVM: ami-074d4d6a02df638da sa-east-1: CISUBUNTU2004: ami-0bba6e05a0a858fbb US2004HVM: ami-0644c2c26649aac62 ca-central-1: CISUBUNTU2004: ami-0b2e07efafe24207e US2004HVM: ami-0efe80e01e2162d9c ap-southeast-1: CISUBUNTU2004: ami-068667925ee812eaa US2004HVM: ami-0c07cd0ceb5369def ap-southeast-2: CISUBUNTU2004: ami-0a94209c1fdf15321 US2004HVM: ami-02e45c427cc633602 eu-central-1: CISUBUNTU2004: ami-016a71be939167dae US2004HVM: ami-0215371f3ea49a91b us-east-1: CISUBUNTU2004: ami-06594bbf095104679 US2004HVM: ami-036490d46656c4818 us-east-2: CISUBUNTU2004: ami-0272d8d921b67573d US2004HVM: ami-044696ab785e77725 us-west-2: CISUBUNTU2004: ami-02d086f8cc9c67825 US2004HVM: ami-0964546d3da97e3ab me-south-1: CISUBUNTU2004: ami-06c6282b68b2271ba US2004HVM: ami-01fafec635e66681c ap-east-1: CISUBUNTU2004: ami-05222f0293e7c7679 US2004HVM: ami-0c98e8b4754246f6b ap-northeast-3: CISUBUNTU2004: ami-0aa2d74a8df8d5037 US2004HVM: ami-067573cd8d4480518 Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, aws-quickstart] InternalLoadBalancer: !Equals [!Ref LoadBalancerType, Internal] CustomDns: !Not [!Equals [!Ref DomainName, '']] CreateDns: !And - !Not - !Equals - !Ref HostedZoneID - '' - !Not - !Equals - !Ref DomainName - '' Resources: # ALB & ACM VaultDNSRecord: Condition: CreateDns Type: AWS::Route53::RecordSet Properties: Type: A Name: !Ref DomainName AliasTarget: HostedZoneId: !GetAtt VaultServerApplicationLoadBalancer.CanonicalHostedZoneID DNSName: !GetAtt VaultServerApplicationLoadBalancer.DNSName HostedZoneId: !Ref HostedZoneID VaultServerApplicationLoadBalancerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: HashiCorp Vault Server Load Balancer VpcId: !Ref VPCID SecurityGroupIngress: - CidrIp: !Ref AccessCIDR IpProtocol: -1 VaultServerApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Subnets: - !If [InternalLoadBalancer, !Ref PrivateSubnet1ID, !Ref PublicSubnet1ID] - !If [InternalLoadBalancer, !Ref PrivateSubnet2ID, !Ref PublicSubnet2ID] - !If [InternalLoadBalancer, !Ref PrivateSubnet3ID, !Ref PublicSubnet3ID] SecurityGroups: - !Ref VaultServerApplicationLoadBalancerSecurityGroup Scheme: !If [InternalLoadBalancer, internal, internet-facing] VaultServerTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: VpcId: !Ref VPCID Port: 8200 Protocol: HTTP Matcher: HttpCode: 200-499 HealthCheckIntervalSeconds: 10 HealthCheckPath: /v1/sys/health?activecode=200&standbycode=200&sealedcode=200&uninitcode=200 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 VaultServerListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: ListenerArn: !Ref VaultServerListenerHTTPS Priority: 1 Conditions: - Field: path-pattern Values: - / Actions: - Type: forward TargetGroupArn: !Ref VaultServerTargetGroup VaultServerListenerHTTPS: Type: AWS::ElasticLoadBalancingV2::Listener Properties: Certificates: - CertificateArn: !If [ CreateDns, !GetAtt ACMCertificate.Outputs.ACMCertificate, !Ref ACMSSLCertificateArn ] DefaultActions: - Type: forward TargetGroupArn: !Ref VaultServerTargetGroup LoadBalancerArn: !Ref VaultServerApplicationLoadBalancer Port: 443 Protocol: HTTPS VaultServerListenerRedirectToHTTPS: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: redirect RedirectConfig: Protocol: HTTPS Port: 443 Host: '#{host}' Path: /#{path} Query: '#{query}' StatusCode: HTTP_301 LoadBalancerArn: !Ref VaultServerApplicationLoadBalancer Port: 80 Protocol: HTTP ACMCertificate: Metadata: cfn-lint: config: ignore_checks: - W9198 Type: AWS::CloudFormation::Stack Condition: CreateDns Properties: TemplateURL: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/quickstart-aws-acm-certificate/templates/quickstart-aws-acm-certificate.template.yml - S3Region: !If [UsingDefaultBucket, !Ref AWS::Region, !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Parameters: QSS3BucketName: !Ref QSS3BucketName QSS3BucketRegion: !Ref QSS3BucketRegion QSS3KeyPrefix: !Sub ${QSS3KeyPrefix}submodules/quickstart-aws-acm-certificate/ DomainName: !Ref DomainName HostedZoneID: !Ref HostedZoneID CopyZipsTemplate: Metadata: cfn-lint: { config: { ignore_checks: [ W9198, W9901 ]}} Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/lambda-copyzips/templates/copy-zips.template.yaml - S3Region: !If [UsingDefaultBucket, !Ref AWS::Region, !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Parameters: QSS3BucketName: !Ref QSS3BucketName QSS3BucketRegion: !Ref QSS3BucketRegion QSS3KeyPrefix: !Ref QSS3KeyPrefix SourceObjects: functions/packages/LeaderElection/lambda.zip,functions/packages/ClusterBootstrap/lambda.zip # Vault will populate this when the cluster is initialized VaultSecret: Type: AWS::SecretsManager::Secret Properties: Name: !Sub VaultSecret-${VaultSecGroup} Description: Vault Root/Recovery key KmsKeyId: !Ref VaultKmsKey SecretString: empty VaultKmsKey: Type: AWS::KMS::Key Metadata: cfn-lint: config: ignore_checks: [EKMSKeyEnableKeyRotation, EIAMPolicyActionWildcard, EIAMPolicyWildcardResource] Properties: Description: Vault Seal/Unseal key KeyPolicy: Version: 2012-10-17 Id: key-default-1 Statement: - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root Action: kms:* Resource: '*' - Sid: Allow administration of the key Effect: Allow Principal: AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${VaultInstanceRole} Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion Resource: '*' - Sid: Allow use of the key Effect: Allow Principal: # If the Lambda Functions need to use this key we must add their execution roles here as principles AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${VaultInstanceRole} Action: - kms:DescribeKey - kms:Encrypt - kms:Decrypt - kms:ReEncrypt* - kms:GenerateDataKey - kms:GenerateDataKeyWithoutPlaintext Resource: '*' VaultSecGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enables SSH access from the Bastion servers. VpcId: !Ref VPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 SourceSecurityGroupId: !Ref BastionSecurityGroupID # Allow the VPC to connect to the vault API of the Cluster - IpProtocol: tcp FromPort: 8200 ToPort: 8200 CidrIp: !Ref VPCCIDR - IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: !Ref VPCCIDR Tags: - Key: Name Value: !Sub ${AWS::StackName}-VaultSecGroup VaultLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub Vault-Audit-Logs-${AWS::StackName} RetentionInDays: 7 # Informs the cluster nodes if they should boot strap VaultLeaderElectedSSM: Type: AWS::SSM::Parameter Properties: Type: String Value: 'false' # This is to know who the elected leader is VaultLeaderSSM: Type: AWS::SSM::Parameter Properties: Type: String Value: 'null' # List of Vault Cluster members managed by Lambda for cluster bootstrap control VaultClusterMembersSSM: Type: AWS::SSM::Parameter Properties: Type: String Value: '{[]}' VaultInstanceRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: [EIAMPolicyActionWildcard, EIAMPolicyWildcardResource] Properties: RoleName: !Sub VaultInstanceRole-${VaultSecGroup} AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: # We provide the Log Group #- logs:CreateLogGroup - logs:CreateLogStream - logs:DescribeLogStreams Resource: - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:Vault-Audit-Logs-${AWS::StackName} - Effect: Allow Action: - logs:PutLogEvents Resource: - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:Vault-Audit-Logs-${AWS::StackName}:log-stream:* - Effect: Allow Action: - ec2:DescribeInstances Resource: '*' - Effect: Allow Action: - ssm:GetParameter Resource: - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultLeaderSSM} - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultClusterMembersSSM} - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultLeaderElectedSSM} - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultKubernetesCertificate} - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultKubernetesJWT} - Effect: Allow Action: - lambda:InvokeFunction Resource: - !GetAtt LeaderElectionLambda.Arn - !GetAtt ClusterBootstrapLambda.Arn - Effect: Allow Action: - autoscaling:Describe* Resource: '*' - Effect: Allow Action: - ec2:DescribeInstances Resource: '*' - Effect: Allow Action: - secretsmanager:UpdateSecretVersionStage - secretsmanager:UpdateSecret - secretsmanager:PutSecretValue - secretsmanager:GetSecretValue Resource: - !Sub arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:VaultSecret-${VaultSecGroup}* - Effect: Allow Action: - iam:GetRole Resource: !GetAtt VaultClientRole.Arn - Action: - s3:GetObject Resource: !Sub - arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}* - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Effect: Allow VaultInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref VaultInstanceRole] VaultServerLaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Properties: LaunchConfigurationName: !Sub VaultLC-${AWS::StackName} InstanceType: !Ref VaultInstanceType KeyName: !Ref KeyPairName SecurityGroups: - !Ref VaultSecGroup ImageId: Fn::FindInMap: - AWSAMIRegionMap - !Ref AWS::Region - !FindInMap - LinuxAMINameMap - !Ref VaultAMIOS - Code BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: 20 VolumeType: gp2 IamInstanceProfile: !Ref VaultInstanceProfile UserData: Fn::Base64: !Sub - | #!/bin/bash -x # Install git apt-get update apt-get install -y git jq zip curl #Load Linux utils until git clone https://github.com/aws-quickstart/quickstart-linux-utilities.git ; do echo "Retrying"; done cd /quickstart-linux-utilities && source quickstart-cfn-tools.source # Prep operating systems qs_update-os || qs_err qs_bootstrap_pip || qs_err qs_aws-cfn-bootstrap || qs_err # Fetch bootstrap script from Bucket & Run export LEADER_ELECTED_SSM_PARAMETER=${VaultLeaderElectedSSM} export LEADER_ID_SSM_PARAMETER=${VaultLeaderSSM} export LEADER_SSM_PARAM=${VaultLeaderSSM} export VAULT_CLUSTER_MEMBERS_SSM_PARAMETER=${VaultClusterMembersSSM} export VAULT_LOG_GROUP=${VaultLogGroup} export AWS_REGION=${AWS::Region} export CFN_STACK_NAME=${AWS::StackName} export LEADER_ELECTION_LAMBDA=${LeaderElectionLambda} export CLUSTER_BOOTSTRAP_LAMBDA=${ClusterBootstrapLambda} export KMS_KEY=${VaultKmsKey} export VAULT_SECRET=VaultSecret-${VaultSecGroup} export VAULT_CLIENT_ROLE=${VaultClientRole.Arn} export VAULT_CLIENT_ROLE_NAME=${VaultClientRoleName} export VAULT_VERSION=${VaultVersion} export VAULT_NUMBER_OF_KEYS=${VaultNumberOfKeys} export VAULT_NUMBER_OF_KEYS_FOR_UNSEAL=${VaultNumberOfKeysForUnseal} export VAULT_KUBERNETES_ENABLE=${VaultKubernetesEnable} export VAULT_KUBERNETES_ROLE_NAME=${VaultKubernetesRoleName} export VAULT_KUBERNETES_HOST_URL=${VaultKubernetesHostURL} export VAULT_KUBERNETES_CERTIFICATE=${VaultKubernetesCertificate} export VAULT_KUBERNETES_JWT=${VaultKubernetesJWT} export VAULT_KUBERNETES_SERVICE_ACCOUNT=${VaultKubernetesServiceAccount} export VAULT_KUBERNETES_NAME_SPACE=${VaultKubernetesNameSpace} export VAULT_KUBERNETES_POLICIES=${VaultKubernetesPolicies} pip install awscli mkdir -p /opt/vault/policies/ /opt/vault/scripts/ /etc/vault.d/ aws s3 cp s3://${S3Bucket}/${QSS3KeyPrefix}scripts/functions.sh . aws s3 cp s3://${S3Bucket}/${QSS3KeyPrefix}scripts/bootstrap_server.sh . chmod +x bootstrap_server.sh $(which bash) -xe ./bootstrap_server.sh /usr/local/bin/cfn-signal -e $? --stack ${!CFN_STACK_NAME} --region ${!AWS_REGION} --resource "VaultServerAutoScalingGroup" # Signalling done from within bootstrap script - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] VaultServerAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Sub VaultServerAutoScalingGroup-${AWS::StackName} LaunchConfigurationName: !Ref VaultServerLaunchConfiguration TargetGroupARNs: - !Ref VaultServerTargetGroup MinSize: !Ref VaultServerNodes MaxSize: !Ref VaultServerNodes DesiredCapacity: !Ref VaultServerNodes VPCZoneIdentifier: - !Ref PrivateSubnet1ID - !Ref PrivateSubnet2ID - !Ref PrivateSubnet3ID Tags: - Key: Name Value: !Sub ${AWS::StackName}-VaultServer PropagateAtLaunch: true CreationPolicy: ResourceSignal: Count: !Ref VaultServerNodes Timeout: PT20M LeaderElectionLambda: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !GetAtt CopyZipsTemplate.Outputs.LambdaZipsBucket S3Key: !Sub ${QSS3KeyPrefix}functions/packages/LeaderElection/lambda.zip Handler: lambda_function.lambda_handler Runtime: python3.9 Environment: Variables: LeaderElectedSSM: !Ref VaultLeaderElectedSSM LeaderSSM: !Ref VaultLeaderSSM AutoScalingGroup: !Sub VaultServerAutoScalingGroup-${AWS::StackName} Timeout: 300 Role: !GetAtt LeaderElectionLambdaExecutionRole.Arn LeaderElectionLambdaExecutionRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: [EIAMPolicyActionWildcard, EIAMPolicyWildcardResource] Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Resource: - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:* Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents # TODO: Restrict permissions to just the SSM Parameters we create - Effect: Allow Resource: - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultLeaderSSM} - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultLeaderElectedSSM} - !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${VaultClusterMembersSSM} Action: - ssm:* # TODO: Restrict to only our AutoScaling group - Effect: Allow Resource: - '*' Action: - autoscaling:DescribeAutoScalingGroups ClusterBootstrapLambda: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !GetAtt CopyZipsTemplate.Outputs.LambdaZipsBucket S3Key: !Sub ${QSS3KeyPrefix}functions/packages/ClusterBootstrap/lambda.zip Handler: lambda_function.lambda_handler Environment: Variables: LeaderElectedSSM: !Ref VaultLeaderElectedSSM LeaderSSM: !Ref VaultLeaderElectedSSM ClusterMembersSSM: !Ref VaultClusterMembersSSM AutoScalingGroup: !Sub VaultServerAutoScalingGroup-${AWS::StackName} Runtime: python3.9 Timeout: 300 Role: !GetAtt ClusterBootstrapLambdaExecutionRole.Arn ClusterBootstrapLambdaExecutionRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: [EIAMPolicyActionWildcard, EIAMPolicyWildcardResource] Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Resource: - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:* Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents # TODO: Restrict permissions to just the SSM Parameters we create - Effect: Allow Resource: - '*' Action: - ssm:* # TODO: Restrict to only our AutoScaling group - Effect: Allow Resource: - '*' Action: - autoscaling:DescribeAutoScalingGroups VaultClientLaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Properties: LaunchConfigurationName: !Sub VaultClientLC-${AWS::StackName} InstanceType: !Ref VaultInstanceType KeyName: !Ref KeyPairName SecurityGroups: - !Ref VaultClientSecurityGroup ImageId: Fn::FindInMap: - AWSAMIRegionMap - !Ref AWS::Region - !FindInMap - LinuxAMINameMap - !Ref VaultAMIOS - Code BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: 20 VolumeType: gp2 IamInstanceProfile: !Ref VaultClientInstanceProfile UserData: Fn::Base64: !Sub - | #!/bin/bash -x # Install git apt-get update apt-get install -y git jq zip curl #Load Linux utils until git clone https://github.com/aws-quickstart/quickstart-linux-utilities.git ; do echo "Retrying"; done cd /quickstart-linux-utilities && source quickstart-cfn-tools.source # Prep operating systems qs_update-os || qs_err qs_bootstrap_pip || qs_err qs_aws-cfn-bootstrap || qs_err # TODO: Fetch script from Bucket && Run export LEADER_SSM_PARAM=${VaultLeaderSSM} export AWS_REGION=${AWS::Region} export CFN_STACK_NAME=${AWS::StackName} export VAULT_CLIENT_ROLE_ID=${VaultClientRole} export VAULT_CLIENT_ROLE_NAME=${VaultClientRoleName} export VAULT_VERSION=${VaultVersion} export ASG_NAME=${VaultServerAutoScalingGroup} pip install awscli mkdir -p /opt/vault/policies/ /opt/vault/scripts/ /etc/vault.d/ aws s3 cp s3://${S3Bucket}/${QSS3KeyPrefix}scripts/functions.sh . aws s3 cp s3://${S3Bucket}/${QSS3KeyPrefix}scripts/bootstrap_client.sh . chmod +x bootstrap_client.sh ./bootstrap_client.sh # Signalling done from within bootstrap script - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] VaultClientAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Sub VaultClientAutoScalingGroup-${AWS::StackName} LaunchConfigurationName: !Ref VaultClientLaunchConfiguration MinSize: !Ref VaultClientNodes MaxSize: !Ref VaultClientNodes DesiredCapacity: !Ref VaultClientNodes VPCZoneIdentifier: - !Ref PrivateSubnet1ID - !Ref PrivateSubnet2ID - !Ref PrivateSubnet3ID Tags: - Key: Name Value: !Sub ${AWS::StackName}-VaultClient PropagateAtLaunch: true CreationPolicy: ResourceSignal: Count: !Ref VaultClientNodes Timeout: PT12M VaultClientSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enables SSH access from the Bastion servers. VpcId: !Ref VPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 SourceSecurityGroupId: !Ref BastionSecurityGroupID - IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: !Ref VPCCIDR Tags: - Key: Name Value: !Sub ${AWS::StackName}-VaultClientSecurityGroup VaultClientInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref VaultClientRole] VaultClientRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: [EIAMPolicyActionWildcard, EIAMPolicyWildcardResource] Properties: # This example allows for an EC2 instance to assume this role. This should be customized for where the Role is being used. Eg: Lambda/Codebuild/EC2 etc. AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: # TODO: Restrict to the Lambda functions LeaderElection/ClusterBootstrapping - Effect: Allow Action: - s3:* Resource: '*' # TODO: Adjust this to be a distinct policy to reference this role. (Circular dependency) #- Effect: Allow # Action: # - sts:AssumeRole # Resource: !GetAtt VaultClientRole.Arn - Effect: Allow Action: - ec2:DescribeInstances - iam:GetInstanceProfile - iam:GetUser - iam:GetRole Resource: '*' - Effect: Allow Action: - autoscaling:DescribeAutoScalingGroups Resource: '*' Outputs: VaultLoadBalancer: Value: !Sub - https://${DNSAddress}/ - DNSAddress: !If [ CustomDns, !Ref DomainName, !GetAtt VaultServerApplicationLoadBalancer.DNSName ] VaultSecret: Value: !Ref VaultSecret Description: The AWS Secrets Manager Secret containing the ROOT TOKEN and Recovery Secret for HashiCorp Vault. VaultClientIAMRoleArn: Value: !GetAtt VaultClientRole.Arn Description: The ARN of the AWS IAM role linked to HashiCorp Vault. VaultClientIAMRoleName: Value: !Ref VaultClientRole Description: The name of the AWS IAM role linked to HashiCorp Vault. VaultKMSKeyId: Value: !Ref VaultKmsKey Description: The AWS KMS Key used to Auto Unseal HashiCorp Vault and encrypt the ROOT TOKEN and Recovery Secret. VaultKMSKeyArn: Value: !GetAtt VaultKmsKey.Arn Description: The AWS KMS Key used to Auto Unseal HashiCorp Vault and encrypt the ROOT TOKEN and Recovery Secret. VaultClientRoleId: Value: !Ref VaultClientRoleName Description: The HashiCorp Vault identifier of the AWS client role. VaultAuditLogGroup: Value: !Ref VaultLogGroup Description: CloudWatch Log Group where the HashiCorp Vault audit logs are recorded