Parameters:
  DomainName:
    Type: String
    Default: 'appmesh-acm-pca-mtls.svc.cluster.local'
    Description: The mesh domain name for setup of ACM PCA mTLS
  
  EnvironmentName:
    Description: An environment name that will be prefixed to resource names
    Type: String

Resources:

  # ---------------------------------------------------------------------------
  # Create Private CA - Color Teller
  # ---------------------------------------------------------------------------
  AcmPcaColorTellerRootCA:
    Type: AWS::ACMPCA::CertificateAuthority
    Properties:
      Type: ROOT
      KeyAlgorithm: RSA_2048
      SigningAlgorithm: SHA256WITHRSA
      Subject:
        CommonName: "AcmPcaColorTeller"

  # ---------------------------------------------------------------------------
  # Create root cert for Private CA Color Teller
  # ---------------------------------------------------------------------------
  AcmPcaColorTellerRootCACert:
    Type: 'AWS::ACMPCA::Certificate'
    Properties:
      CertificateAuthorityArn: !Ref AcmPcaColorTellerRootCA
      CertificateSigningRequest: !GetAtt
        - AcmPcaColorTellerRootCA
        - CertificateSigningRequest
      SigningAlgorithm: SHA256WITHRSA
      TemplateArn: !Sub 'arn:${AWS::Partition}:acm-pca:::template/RootCACertificate/V1'
      Validity:
        Type: YEARS
        Value: 10

  # ---------------------------------------------------------------------------
  # Activate Private CA Color Teller -
  # Associates Root CA with Root Cert
  # ---------------------------------------------------------------------------
  AcmPcaColorTellerRootCAActivation:
    Type: 'AWS::ACMPCA::CertificateAuthorityActivation'
    Properties:
      CertificateAuthorityArn: !Ref AcmPcaColorTellerRootCA
      Certificate: !GetAtt
        - AcmPcaColorTellerRootCACert
        - Certificate
      Status: ACTIVE

  # ---------------------------------------------------------------------------
  # Create endpoint cert for Color Teller app mesh node
  # TODO
  # ---------------------------------------------------------------------------
  AcmPcaColorTellerEndpointCert:
    Type: AWS::CertificateManager::Certificate
    DependsOn: AcmPcaColorTellerRootCAActivation
    Properties:
      CertificateAuthorityArn: !Ref AcmPcaColorTellerRootCA
      DomainName: !Sub 'colorteller.${DomainName}'



  # ---------------------------------------------------------------------------
  # Create Private CA - Color Gateway
  # ---------------------------------------------------------------------------
  AcmPcaColorGatewayRootCA:
    Type: AWS::ACMPCA::CertificateAuthority
    Properties:
      Type: ROOT
      KeyAlgorithm: RSA_2048
      SigningAlgorithm: SHA256WITHRSA
      Subject:
        CommonName: "AcmPcaColorGateway"

  # ---------------------------------------------------------------------------
  # Create root cert for Private CA Color Gateway
  # ---------------------------------------------------------------------------
  AcmPcaColorGatewayRootCACert:
    Type: 'AWS::ACMPCA::Certificate'
    Properties:
      CertificateAuthorityArn: !Ref AcmPcaColorGatewayRootCA
      CertificateSigningRequest: !GetAtt
        - AcmPcaColorGatewayRootCA
        - CertificateSigningRequest
      SigningAlgorithm: SHA256WITHRSA
      TemplateArn: !Sub 'arn:${AWS::Partition}:acm-pca:::template/RootCACertificate/V1'
      Validity:
        Type: YEARS
        Value: 10

  # ---------------------------------------------------------------------------
  # Activate Private CA Color Gateway -
  # Associates Root CA with Root Cert
  # ---------------------------------------------------------------------------
  AcmPcaColorGatewayRootCAActivation:
    Type: 'AWS::ACMPCA::CertificateAuthorityActivation'
    Properties:
      CertificateAuthorityArn: !Ref AcmPcaColorGatewayRootCA
      Certificate: !GetAtt
        - AcmPcaColorGatewayRootCACert
        - Certificate
      Status: ACTIVE

  # ---------------------------------------------------------------------------
  # Create endpoint cert for Color Gateway app mesh node
  # ---------------------------------------------------------------------------
  AcmPcaColorGatewayEndpointCert:
    Type: AWS::CertificateManager::Certificate
    DependsOn: AcmPcaColorGatewayRootCAActivation
    Properties:
      CertificateAuthorityArn: !Ref AcmPcaColorGatewayRootCA
      DomainName: !Sub 'colorgateway.${DomainName}'
  
  SecretCert:
    Type: AWS::SecretsManager::Secret
    Properties:
      SecretString: |
        {
          "GatewayCertificate": "tempcert",
          "GatewayCertificateChain": "tempcertchain",
          "GatewayPrivateKey": "privatekey",
          "Passphrase": "passphrase"
        }

  InitCertRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: [lambda.amazonaws.com]
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
      Policies:
        - PolicyName: acm-secretsmanager-access
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: acm:ExportCertificate
                Resource: 
                  - !Ref AcmPcaColorGatewayEndpointCert
                  - !Ref AcmPcaColorTellerEndpointCert
              - Effect: Allow
                Action:
                  - secretsmanager:GetRandomPassword
                Resource: '*'
              - Effect: Allow
                Action: secretsmanager:PutSecretValue
                Resource: !Ref SecretCert
              - Effect: Allow
                Action: acm-pca:CreatePermission
                Resource:
                  - !Ref AcmPcaColorGatewayRootCA
                  - !Ref AcmPcaColorTellerRootCA

  InitCertFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: Initial function to populate secrets manager from ACM
      Handler: index.lambda_handler
      Role: !GetAtt InitCertRole.Arn
      Runtime: python3.8
      Timeout: 900
      Environment:
        Variables:
          COLOR_GATEWAY_ACM_ARN: !Ref AcmPcaColorGatewayEndpointCert
          COLOR_TELLER_ACM_ARN: !Ref AcmPcaColorTellerEndpointCert
          COLOR_TELLER_ACM_PCA_ARN: !Ref AcmPcaColorTellerRootCA
          COLOR_GATEWAY_ACM_PCA_ARN: !Ref AcmPcaColorGatewayRootCA
          AWS_ACCOUNT: !Ref 'AWS::AccountId'
          SECRET: !Ref SecretCert
      Code:
        ZipFile: |
          import json
          import boto3
          import base64
          import os
          import cfnresponse
          sm = boto3.client('secretsmanager')
          cm = boto3.client('acm')
          pca = boto3.client('acm-pca')
          gate_cm = os.environ['COLOR_GATEWAY_ACM_ARN']
          teller_cm = os.environ['COLOR_TELLER_ACM_ARN']
          teller_pca_cm = os.environ['COLOR_TELLER_ACM_PCA_ARN']
          gateway_pca_cm = os.environ['COLOR_GATEWAY_ACM_PCA_ARN']
          acc_id = os.environ['AWS_ACCOUNT']
          secret = os.environ['SECRET']
          def lambda_handler(event, context):
            print (json.dumps(event))
            if (event['RequestType'] == 'Delete') or (event['RequestType'] == 'Update'):
              cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, '')
            elif event['RequestType'] == 'Create':
              try:
                pca.create_permission(
                  CertificateAuthorityArn=teller_pca_cm,
                  Principal='acm.amazonaws.com',
                  SourceAccount=acc_id,
                  Actions=[
                    'IssueCertificate',
                    'GetCertificate',
                    'ListPermissions'
                  ]
                )
                pca.create_permission(
                  CertificateAuthorityArn=gateway_pca_cm,
                  Principal='acm.amazonaws.com',
                  SourceAccount=acc_id,
                  Actions=[
                    'IssueCertificate',
                    'GetCertificate',
                    'ListPermissions'
                  ]
                )
                passphrase = sm.get_random_password(ExcludePunctuation=True)['RandomPassword']
                passphrase_enc = base64.b64encode(passphrase.encode('utf-8'))
                cm.export_certificate(CertificateArn=teller_cm, Passphrase=passphrase_enc)
                gate_rsp = cm.export_certificate(CertificateArn=gate_cm, Passphrase=passphrase_enc)
                sm_value={}
                sm_value['GatewayCertificate']=gate_rsp['Certificate']
                sm_value['GatewayCertificateChain']=gate_rsp['CertificateChain']
                sm_value['GatewayPrivateKey']=gate_rsp['PrivateKey']
                sm_value['Passphrase']=passphrase
                sm.put_secret_value(SecretId=secret, SecretString=json.dumps(sm_value))
                cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, '')
              except Exception as e:
                print(e) 
                cfnresponse.send(event, context, cfnresponse.FAILED, {}, '')



  InitCert:
    Type: Custom::InitCert
    Properties:
      ServiceToken: !GetAtt InitCertFunction.Arn
      Secret: !Ref SecretCert


Outputs:
  AcmPcaColorTellerEndpointCertArn:
    Value: !Ref AcmPcaColorTellerEndpointCert
    Export:
      Name: !Sub "${EnvironmentName}:AcmPcaColorTellerEndpointCertArn"
  AcmPcaColorGatewayEndpointCertArn:
    Value: !Ref AcmPcaColorGatewayEndpointCert
    Export:
      Name: !Sub "${EnvironmentName}:AcmPcaColorGatewayEndpointCertArn"
  AcmPcaColorTellerRootCAArn:
    Value: !Ref AcmPcaColorTellerRootCA
    Export:
      Name: !Sub "${EnvironmentName}:AcmPcaColorTellerRootCAArn"
  AcmPcaColorGatewayRootCAArn:
    Value: !Ref AcmPcaColorGatewayRootCA
    Export:
      Name: !Sub "${EnvironmentName}:AcmPcaColorGatewayRootCAArn"
  SecretCertArn:
    Value: !Ref SecretCert
    Export:
      Name: !Sub "${EnvironmentName}:SecretCertArn"