AWSTemplateFormatVersion: "2010-09-09" Description: "Deploys the HashiCorp Vault Helm chart on an Amazon EKS cluster (qs-1r79drkr6)" Metadata: LintSpellExclude: - Kubernetes - namespace - HashiCorp - Vault - balancer - vault-ui - Auto Scaling - Hosted - Domain # QSLint: # Exclusions: [W9002, W9003, W9004, W9006] QuickStartDocumentation: EntrypointName: "Launch into an existing Amazon EKS cluster" AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Amazon EKS cluster Parameters: - ClusterName - Label: default: Network configuration Parameters: - AccessCIDR - PrivateSubnet1ID - PrivateSubnet2ID - PrivateSubnet3ID - HttpProxy - KeyPairName - Label: default: HashiCorp Vault Configuration Parameters: - VaultVersion - VaultDeploymentSize - KubernetesNameSpace - LoadBalancerType - DomainName - HostedZoneID - ACMSSLCertificateArn - Nodes - Label: default: Quick Start Configuration Parameters: - QSS3BucketName - QSS3BucketRegion - QSS3KeyPrefix ParameterLabels: 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 for Vault UI KubernetesNameSpace: default: Kubernetes namespace for Vault 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 LoadBalancerType: default: Internal or external load balancer? ACMSSLCertificateArn: default: ACM SSL certificate ARN HostedZoneID: default: Route 53–hosted zone ID DomainName: default: Load balancer DNS name VaultVersion: default: HashiCorp Vault version VaultDeploymentSize: default: HashiCorp Vault deployment size Nodes: default: HashiCorp Vault server nodes ClusterName: default: Amazon EKS cluster name HttpProxy: default: HTTP proxy Parameters: ClusterName: Type: String Description: Amazon EKS cluster. KeyPairName: Type: "AWS::EC2::KeyPair::KeyName" Description: Name of an existing key pair, which helps to secure your connection to instances after they launch. PrivateSubnet1ID: Type: "AWS::EC2::Subnet::Id" Description: ID of the private subnet in Availability Zone 1 of your existing VPC (e.g., subnet-fe9a8b32). PrivateSubnet2ID: Type: "AWS::EC2::Subnet::Id" Description: ID of the private subnet in Availability Zone 2 of your existing VPC (e.g., subnet-fe9a8b32). PrivateSubnet3ID: Type: "AWS::EC2::Subnet::Id" Description: ID of the private subnet in Availability Zone 3 of your existing VPC (e.g., subnet-fe9a8b32). VaultVersion: Type: String Default: "1.6.0" Description: Version of Vault to use. AllowedValues: - "1.6.0" VaultDeploymentSize: Type: String Default: "small" Description: Deployment size of dedicated HashiCorp Vault nodes. (see https://learn.hashicorp.com/tutorials/vault/kubernetes-reference-architecture). AllowedValues: - "small" - "medium" - "large" KubernetesNameSpace: Default: "vault-server" Type: String Description: Kubernetes namespace for HashiCorp Vault server. Nodes: Type: Number Default: "3" AllowedValues: - "3" Description: Number of dedicated Vault server nodes and pods. HttpProxy: Type: String Default: "" Description: HTTP proxy server address e.g. "http://10.32.20.10:3128/." LoadBalancerType: Type: String Default: "Internal" Description: Choose whether the load balancer for HashiCorp Vault is internal or external to the VPC. AllowedValues: - "Internal" - "External" 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: "CIDR IP range that is permitted to access Vault. Note that a value of 0.0.0.0/0 allows access from any IP address." Default: 127.0.0.1/32 Type: String DomainName: Type: String Description: >- Fully qualified DNS name for the "vault-ui" service load balancer. If you don't provide a value for "ACM SSL certificate ARN", use "HostedZoneID." MaxLength: 128 Default: "" HostedZoneID: Type: String Description: >- Route 53–hosted zone ID of the domain name. If you don't provide a value for "ACMSSLCertificateArn,"" the Quick Start creates an ACM certificate for you using "HostedZoneID" in conjunction with the domain name. Default: "" ACMSSLCertificateArn: Description: >- ARN of the load balancer's ACM SSL certificate. If you don't provide values for "Domain name" and "HostedZoneID," provide a value for "ACM SSL certificate ARN." Type: String Default: "" 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-eks-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 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' - '' Mappings: Scaling: small: InstanceType: "m5.large" VolumeSize: "25" medium: InstanceType: "m5.xlarge" VolumeSize: "50" large: InstanceType: "m5.2xlarge" VolumeSize: "50" Resources: GetClusterVPCID: Type: Custom::GetClusterVPCID Properties: ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" AwsCliCommand: !Sub "eks describe-cluster --name ${ClusterName} --query 'cluster.resourcesVpcConfig.{vpcId:vpcId}'" IdField: 'vpcId' GetClusterSecurityGroupId: Type: Custom::GetClusterSecurityGroupId Properties: ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" AwsCliCommand: !Sub "eks describe-cluster --name ${ClusterName} --query 'cluster.resourcesVpcConfig.{clusterSecurityGroupId:clusterSecurityGroupId}'" IdField: 'clusterSecurityGroupId' GetClusterKubernetesVersion: Type: Custom::GetClusterKubernetesVersion Properties: ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" AwsCliCommand: !Sub "eks describe-cluster --name ${ClusterName} --query 'cluster.{version:version}'" IdField: 'version' GetOIDCProvider: Type: Custom::GetOIDCProvider Properties: ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" AwsCliCommand: !Sub "eks describe-cluster --name ${ClusterName} --query 'cluster.identity.oidc.{issuer:issuer}'" IdField: 'issuer' VaultNodeGroup: Metadata: cfn-lint: {config: {ignore_checks: [W9901]}} # Default values in submodule template Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/quickstart-amazon-eks-nodegroup/templates/amazon-eks-nodegroup.template.yaml' - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Parameters: HttpProxy: !Ref HttpProxy KeyPairName: !Ref 'KeyPairName' Subnet1ID: !Ref PrivateSubnet1ID Subnet2ID: !Ref PrivateSubnet2ID Subnet3ID: !Ref PrivateSubnet3ID NodeInstanceType: !FindInMap [ "Scaling", !Ref VaultDeploymentSize, "InstanceType" ] NumberOfNodes: !Ref Nodes MaxNumberOfNodes: !Ref Nodes NodeGroupName: !Sub "Vault-${PsuedoRandom.GroupId}" NodeVolumeSize: !FindInMap [ "Scaling", !Ref VaultDeploymentSize, "VolumeSize" ] EKSClusterName: !Ref ClusterName ACMCertificate: Metadata: cfn-lint: config: ignore_checks: - W9196 - W9197 - W9198 - W9199 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 VaultSecurityGroup: Metadata: cfn-lint: {config: {ignore_checks: [E3008]}} # Parameter type mismatch Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enables SSH access from the bastion servers. VpcId: !Ref GetClusterVPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: !Ref AccessCIDR - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: !Ref AccessCIDR Tags: - Key: Name Value: Fn::Join: - "-" - - Ref: AWS::StackName - VaultSecGroup PsuedoRandom: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: DoNotUse VaultUnsealRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "VaultUnsealIAMRole-${PsuedoRandom.GroupId}" AssumeRolePolicyDocument: !Sub - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${OIDCProvider}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDCProvider}:sub": "system:serviceaccount:${NameSpace}:${ResourceName}-${PsuedoRandom.GroupId}" } } } ] } - NameSpace: !Ref KubernetesNameSpace ResourceName: vault # https://oidc.eks.eu-west-1.amazonaws.com/id/8371C1E71D49834A7595BB4D1850E140 OIDCProvider: !Sub - "${OIDCProvider1}/${OIDCProvider2}/${OIDCProvider3}" - OIDCProvider1: !Select [ 2, !Split [ "/", !Ref GetOIDCProvider ] ] OIDCProvider2: !Select [ 3, !Split [ "/", !Ref GetOIDCProvider ] ] OIDCProvider3: !Select [ 4, !Split [ "/", !Ref GetOIDCProvider ] ] Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:GetRole Resource: !Sub "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:role/VaultUnsealIAMRole-${PsuedoRandom.GroupId}" - Effect: Allow Action: - kms:* Resource: "*" VaultRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "VaultIAMRole-${PsuedoRandom.GroupId}" AssumeRolePolicyDocument: !Sub - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${OIDCProvider}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDCProvider}:sub": "system:serviceaccount:${NameSpace}:${ResourceName}" } } } ] } - NameSpace: !Ref KubernetesNameSpace ResourceName: !Sub "boot-vault-${PsuedoRandom.GroupId}" # https://oidc.eks.eu-west-1.amazonaws.com/id/8371C1E71D49834A7595BB4D1850E140 OIDCProvider: !Sub - "${OIDCProvider1}/${OIDCProvider2}/${OIDCProvider3}" - OIDCProvider1: !Select [ 2, !Split [ "/", !Ref GetOIDCProvider ] ] OIDCProvider2: !Select [ 3, !Split [ "/", !Ref GetOIDCProvider ] ] OIDCProvider3: !Select [ 4, !Split [ "/", !Ref GetOIDCProvider ] ] Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 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: - s3:* Resource: - "*" - Effect: Allow Action: - secretsmanager:UpdateSecretVersionStage - secretsmanager:UpdateSecret - secretsmanager:PutSecretValue - secretsmanager:GetSecretValue Resource: - !Sub "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:VaultSecret-${PsuedoRandom.GroupId}*" - Effect: Allow Action: - iam:GetRole Resource: !Sub "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:role/VaultIAMRole-${PsuedoRandom.GroupId}" VaultKmsKey: Type: AWS::KMS::Key DependsOn: [ VaultRole, VaultUnsealRole ] 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:iam::${AWS::AccountId}:root" Action: kms:* Resource: '*' - Sid: Allow administration of the key Effect: Allow Principal: AWS: - !Sub "arn:aws:iam::${AWS::AccountId}:role/VaultIAMRole-${PsuedoRandom.GroupId}" - !Sub "arn:aws:iam::${AWS::AccountId}:role/VaultUnsealIAMRole-${PsuedoRandom.GroupId}" 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:iam::${AWS::AccountId}:role/VaultIAMRole-${PsuedoRandom.GroupId}" - !Sub "arn:aws:iam::${AWS::AccountId}:role/VaultUnsealIAMRole-${PsuedoRandom.GroupId}" Action: - kms:DescribeKey - kms:Encrypt - kms:Decrypt - kms:ReEncrypt* - kms:GenerateDataKey - kms:GenerateDataKeyWithoutPlaintext Resource: '*' VaultSecret: Type: AWS::SecretsManager::Secret Properties: Name: !Sub "VaultSecret-${PsuedoRandom.GroupId}" Description: "Vault Root/Recovery key" KmsKeyId: !Ref VaultKmsKey SecretString: "empty" VaultNameSpace: Type: "AWSQS::Kubernetes::Resource" Properties: ClusterName: !Ref ClusterName Namespace: default Manifest: !Sub | kind: Namespace apiVersion: v1 metadata: name: ${KubernetesNameSpace} HashicorpVaultHelmChart: Type: "AWSQS::Kubernetes::Helm" DependsOn: [ VaultNodeGroup, VaultCertificatesJob ] Properties: ClusterID: !Ref ClusterName Repository: https://helm.releases.hashicorp.com Namespace: !Ref KubernetesNameSpace Name: !Sub "vault-${PsuedoRandom.GroupId}" Chart: hashicorp/vault ValueYaml: !Sub - | global: tlsDisable: false ui: enabled: true externalPort: 443 serviceType: "LoadBalancer" loadBalancerSourceRanges: - ${AccessCIDR} annotations: | service.beta.kubernetes.io/aws-load-balancer-ssl-cert: ${SSLCertificate} service.beta.kubernetes.io/aws-load-balancer-backend-protocol: https service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8200" service.beta.kubernetes.io/do-loadbalancer-healthcheck-path: "/ui/" ${IsInternalLoadBalancer} ${ExternalName} ${TTL} server: nodeSelector: | eks.amazonaws.com/nodegroup: Vault-${PsuedoRandom.GroupId} extraEnvironmentVars: VAULT_CACERT: /vault/userconfig/vault-server-tls/vault.ca extraVolumes: - type: secret name: vault-server-tls image: repository: "vault" tag: ${VaultVersion} logLevel: "debug" serviceAccount: annotations: !Sub | eks.amazonaws.com/role-arn: "arn:aws:iam::${AWS::AccountId}:role/VaultUnsealIAMRole-${PsuedoRandom.GroupId}" extraEnvironmentVars: # for 1.4.3 no auto assigned name AWS_ROLE_SESSION_NAME: some_name ha: enabled: true nodes: ${Nodes} raft: enabled: true setNodeId: true config: | ui = true listener "tcp" { tls_disable = 0 tls_cert_file = "/vault/userconfig/vault-server-tls/vault.crt" tls_key_file = "/vault/userconfig/vault-server-tls/vault.key" tls_client_ca_file = "/vault/userconfig/vault-server-tls/vault.ca" address = "[::]:8200" cluster_address = "[::]:8201" } storage "raft" { path = "/vault/data" } service_registration "kubernetes" {} seal "awskms" { region = "${AWS::Region}" kms_key_id = "${VaultKmsKey}" } - SSLCertificate: !If [ CreateDns, !GetAtt "ACMCertificate.Outputs.ACMCertificate", !Ref "ACMSSLCertificateArn" ] IsInternalLoadBalancer: !If [ InternalLoadBalancer , 'service.beta.kubernetes.io/aws-load-balancer-internal: "true"', 'service.beta.kubernetes.io/aws-load-balancer-internal: "false"' ] # SecurityGroups: !Sub "service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: ${VaultSecurityGroup}" # QuotedDomainName: !If [ CreateDns, !Sub "'${DomainName}'", "" ] # DNSSAN: !If [ CreateDns, !Sub 'serverAdditionalDNSSANs: ["${QuotedDomainName}"]', !Sub "{AWS::NoValue}"] ExternalName: !If [ CreateDns, !Sub '"external-dns.alpha.kubernetes.io/hostname": "${DomainName}"', "" ] TTL: !If [ CreateDns, 'external-dns.alpha.kubernetes.io/ttl: "30"', "" ] VaultClusterRole: Type: "AWSQS::Kubernetes::Resource" DependsOn: VaultNameSpace Properties: ClusterName: !Ref ClusterName Namespace: !Ref KubernetesNameSpace Manifest: !Sub - | apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/name: ${ResourceName} name: ${ResourceName} # Modify for your scripts here rules: - apiGroups: - "" resources: - pods/exec - pods - pods/log - secrets - tmp/secrets verbs: - get - list - create - apiGroups: - "certificates.k8s.io" resources: - "certificatesigningrequests" - "certificatesigningrequests/approval" verbs: - update - get - list - create - ResourceName: !Sub "boot-vault-${PsuedoRandom.GroupId}" VaultServiceAccount: Type: "AWSQS::Kubernetes::Resource" DependsOn: [ VaultNameSpace, VaultClusterRole ] Properties: ClusterName: !Ref ClusterName Namespace: !Ref KubernetesNameSpace Manifest: !Sub - | apiVersion: v1 kind: ServiceAccount metadata: labels: app.kubernetes.io/name: ${ResourceName} annotations: eks.amazonaws.com/role-arn: arn:aws:iam::${AWS::AccountId}:role/${RoleName} name: ${ResourceName} namespace: ${NameSpace} - ResourceName: !Sub "boot-vault-${PsuedoRandom.GroupId}" NameSpace: !Ref KubernetesNameSpace RoleName: !Sub "VaultIAMRole-${PsuedoRandom.GroupId}" VaultInitialisationJob: Type: "AWSQS::Kubernetes::Resource" DependsOn: [ VaultClusterRoleBinding, VaultCertificatesJob ] Properties: ClusterName: !Ref ClusterName Namespace: !Ref KubernetesNameSpace Manifest: !Sub - | apiVersion: batch/v1 kind: Job metadata: name: ${ResourceName} namespace: ${NameSpace} spec: template: spec: containers: - name: ${ResourceName} image: amazonlinux command: ["/bin/bash","-c"] args: - > sleep 15; yum install -y awscli 2>&1 > /dev/null; export AWS_REGION=${AWS::Region}; export RELEASE_NAME=${ReleaseName}; aws sts get-caller-identity; aws s3 cp ${!S3_SCRIPT_URL} ./script.sh && chmod +x ./script.sh && ./script.sh env: - name: S3_SCRIPT_URL value: ${S3ScriptURL} - name: VAULT_SECRET value: ${VaultSecret} serviceAccountName: ${ResourceName} restartPolicy: Never backoffLimit: 4 - ResourceName: !Sub "boot-vault-${PsuedoRandom.GroupId}" NameSpace: !Ref KubernetesNameSpace ReleaseName: !Sub "${PsuedoRandom.GroupId}" S3ScriptURL: !Sub "s3://${QSS3BucketName}/${QSS3KeyPrefix}scripts/bootstrap.sh" VaultCertificatesJob: Type: "AWSQS::Kubernetes::Resource" DependsOn: [ VaultNameSpace, VaultClusterRoleBinding ] Properties: ClusterName: !Ref ClusterName Namespace: !Ref KubernetesNameSpace Manifest: !Sub - | apiVersion: batch/v1 kind: Job metadata: name: ${ResourceName} namespace: ${NameSpace} spec: template: spec: containers: - name: ${ResourceName} image: amazonlinux command: ["/bin/bash","-c"] args: - > sleep 15; yum install -y awscli 2>&1 > /dev/null; export AWS_REGION=${AWS::Region}; export RELEASE_NAME=${ReleaseName}; export NAMESPACE=${NameSpace}; aws sts get-caller-identity; aws s3 cp ${!S3_SCRIPT_URL} ./script.sh && chmod +x ./script.sh && ./script.sh env: - name: S3_SCRIPT_URL value: ${S3ScriptURL} - name: NAME_SPACE value: ${NameSpace} serviceAccountName: ${ServiceAccount} restartPolicy: Never backoffLimit: 4 - ResourceName: !Sub "certificate-vault-${PsuedoRandom.GroupId}" ServiceAccount: !Sub "boot-vault-${PsuedoRandom.GroupId}" NameSpace: !Ref KubernetesNameSpace ReleaseName: !Sub "${PsuedoRandom.GroupId}" S3ScriptURL: !Sub "s3://${QSS3BucketName}/${QSS3KeyPrefix}scripts/certificates.sh" VaultClusterRoleBinding: Type: "AWSQS::Kubernetes::Resource" DependsOn: [ VaultNameSpace, VaultRole, VaultClusterRole, VaultServiceAccount ] Properties: ClusterName: !Ref ClusterName Namespace: default Manifest: !Sub - | apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/name: ${ResourceName} name: ${ResourceName} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ${ResourceName} subjects: - kind: ServiceAccount name: ${ResourceName} namespace: ${NameSpace} - ResourceName: !Sub "boot-vault-${PsuedoRandom.GroupId}" NameSpace: !Ref KubernetesNameSpace GetELBDetail: DependsOn: HashicorpVaultHelmChart Type: "AWSQS::Kubernetes::Get" Properties: ClusterName: !Ref "ClusterName" Name: !Sub "service/vault-${PsuedoRandom.GroupId}-ui" Namespace: !Ref "KubernetesNameSpace" JsonPath: "{.status.loadBalancer.ingress[0].hostname}" GetELBHostedZone: Type: Custom::GetELBHostedZone Properties: ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" AwsCliCommand: !Sub - "elb describe-load-balancers --load-balancer-names ${elbname} --query 'LoadBalancerDescriptions[0].{HostedZoneId:CanonicalHostedZoneNameID}'" - elbname: !Select [ 0, !Split ["-", !Sub "${GetELBDetail.Response}" ] ] IdField: 'HostedZoneId' ELBDNSRecord: Condition: CreateDns Type: AWS::Route53::RecordSet Properties: Type: A Name: !Ref "DomainName" AliasTarget: HostedZoneId: !Ref "GetELBHostedZone" DNSName: !Sub "${GetELBDetail.Response}" HostedZoneId: !Ref "HostedZoneID" Outputs: HashicorpVaultReleaseName: Value: !Sub "vault-${PsuedoRandom.GroupId}" VaultLoadBalancer: Value: !Sub - "https://${DNSAddress}/" - DNSAddress: !If [ CustomDns, !Ref DomainName, !Sub "${GetELBDetail.Response}" ] VaultSecret: Value: !Ref "VaultSecret" Description: AWS Secrets Manager secret that contains the root token and recovery secret for HashiCorp Vault. VaultKMSKeyArn: Value: !GetAtt "VaultKmsKey.Arn" Description: AWS KMS Key used to Auto Unseal HashiCorp Vault and encrypt the root token and recovery secret. Rules: DomainNamePresentWithHostedID: RuleCondition: !Equals [ !Ref HostedZoneID, '' ] Assertions: - Assert: !Not [!Equals [!Ref DomainName, '']] AssertDescription: "Specify 'DomainName' if you specified 'Route 53–hosted zone ID.'" HostedIDPresentWithDomainName: RuleCondition: !Equals [ !Ref DomainName, '' ] Assertions: - Assert: !Not [!Equals [!Ref HostedZoneID, '']] AssertDescription: "Specify a 'Route 53 Hosted Zone ID' if you specified 'DomainName.''" GenerateOrProvideSSL: RuleCondition: !Not [!Equals [!Ref ACMSSLCertificateArn, '']] Assertions: - Assert: !And - !Equals [!Ref HostedZoneID, ''] - !Equals [!Ref DomainName, ''] AssertDescription: "Using an SSL certificate is enforced. A 'CertificateArn' or a 'HostedZoneID' and domain name must be provided." NoLoadBalancerInfoSupplied: Assertions: - Assert: !Or - !Not [!Equals [!Ref HostedZoneID, '']] - !Not [!Equals [!Ref ACMSSLCertificateArn, '']] - !Not [!Equals [!Ref DomainName, '']] AssertDescription: "Using an SSL certificate is enforced. A CertificateArn or a HostedZoneID and Domain Name must be provided."