Cloudformationを使ったプライベートCA構築~証明書発行

2020.01.29

はじめに

こんにちは。大阪オフィスの林です。

アップデートのチェックをしていたら「AWS Certificate Manager プライベート認証機関が、CloudFormation リソースの提供開始」と出てきたのでやってみました。公式ページはこちら

注意点

プライベートCAには無料のトライアル期間も御座いますが、下記のようなコストがかかります。(2020年1月31日時点)

  • CA を削除するまで、ACM プライベート CA ごとに毎月 400 USD。
  • ACM プライベート CA の運用は、1 か月に満たない月は、CA の作成、削除の日に応じて日割りで料金をお支払いただきます。削除すると、プライベート CA は課金されなくなります。ただし、削除した CA を復元した場合は、削除から復元までの期間について課金されます。
  • 私は検証のために触っていたのですが思いのほかコストがかかってしまっていたので、注意喚起させて頂きます。

    CFnテンプレート

    基本的にはサンプルで用意されている内容を引用しています。各種パラメータはこちらを参照ください。
    今回はルートCA1つと、そのルートCAに紐づく下位CAを2つ作っていきます。

    AWSTemplateFormatVersion: 2010-09-09
    Description: Cloudformation template to setup CA.
    
    Resources:
    #プライベートのルートCAを作成します。
      RootCA:
        Type: 'AWS::ACMPCA::CertificateAuthority'
        Properties:
          Type: ROOT
          KeyAlgorithm: RSA_2048
          SigningAlgorithm: SHA256WITHRSA
          Subject:
            Country: JP
            Organization: test-Organization
            OrganizationalUnit: test-OrganizationalUnit
            DistinguishedNameQualifier: test-DistinguishedNameQualifier
            State: test-State
            CommonName: 'test-CommonName'
            SerialNumber: 123456789
            Locality: test-Locality
            Title: test-Title
            Surname: test-Surname
            GivenName: test-GivenName
            Initials: MH
            Pseudonym: test-Pseudonym
            GenerationQualifier: test-GenerationQualifier
          RevocationConfiguration:
            CrlConfiguration:
              Enabled: false
      RootCACertificate:
        Type: 'AWS::ACMPCA::Certificate'
        Properties:
          CertificateAuthorityArn: !Ref RootCA
          CertificateSigningRequest: !GetAtt 
            - RootCA
            - CertificateSigningRequest
          SigningAlgorithm: SHA256WITHRSA
          TemplateArn: 'arn:aws:acm-pca:::template/RootCACertificate/V1'
          Validity:
            Type: DAYS
            Value: 100
      RootCAActivation:
        Type: 'AWS::ACMPCA::CertificateAuthorityActivation'
        Properties:
          CertificateAuthorityArn: !Ref RootCA
          Certificate: !GetAtt 
            - RootCACertificate
            - Certificate
          Status: ACTIVE
    
     #プライベートの下位CA(1つ目)を作成します。
      SubordinateCAOne:
        Type: 'AWS::ACMPCA::CertificateAuthority'
        Properties:
          Type: SUBORDINATE
          KeyAlgorithm: RSA_2048
          SigningAlgorithm: SHA256WITHRSA
          Subject:
            Country: JP
            Organization: test-Organization
            OrganizationalUnit: test-OrganizationalUnit
            DistinguishedNameQualifier: test-DistinguishedNameQualifier
            State: test-State
            CommonName: 'test-sub1-CommonName'
            SerialNumber: 123456789
            Locality: test-Locality
            Title: test-Title
            Surname: test-Surname
            GivenName: test-GivenName
            Initials: MH
            Pseudonym: test-Pseudonym
            GenerationQualifier: test-GenerationQualifier
          RevocationConfiguration: {}
          Tags: []
      SubordinateCAOneCACertificate:
        DependsOn: RootCAActivation
        Type: 'AWS::ACMPCA::Certificate'
        Properties:
          CertificateAuthorityArn: !Ref RootCA
          CertificateSigningRequest: !GetAtt 
            - SubordinateCAOne
            - CertificateSigningRequest
          SigningAlgorithm: SHA256WITHRSA
          TemplateArn: 'arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen3/V1'
          Validity:
            Type: DAYS
            Value: 90
      SubordinateCAOneActivation:
        Type: 'AWS::ACMPCA::CertificateAuthorityActivation'
        Properties:
          CertificateAuthorityArn: !Ref SubordinateCAOne
          Certificate: !GetAtt 
            - SubordinateCAOneCACertificate
            - Certificate
          CertificateChain: !GetAtt 
            - RootCAActivation
            - CompleteCertificateChain
          Status: ACTIVE
    
     #プライベートの下位CA(2つ目)を作成します。
      SubordinateCATwo:
        Type: 'AWS::ACMPCA::CertificateAuthority'
        Properties:
          Type: SUBORDINATE
          KeyAlgorithm: RSA_2048
          SigningAlgorithm: SHA256WITHRSA
          Subject:
            Country: JP
            Organization: test-Organization
            OrganizationalUnit: test-OrganizationalUnit
            DistinguishedNameQualifier: test-DistinguishedNameQualifier
            State: test-State
            CommonName: 'test-sub2-CommonName'
            SerialNumber: 123456789
            Locality: test-Locality
            Title: test-Title
            Surname: test-Surname
            GivenName: test-GivenName
            Initials: MH
            Pseudonym: test-Pseudonym
            GenerationQualifier: test-GenerationQualifier
          Tags:
            - Key: Key1
              Value: Value1
            - Key: Key2
              Value: Value2
      SubordinateCATwoCACertificate:
        DependsOn: SubordinateCAOneActivation
        Type: 'AWS::ACMPCA::Certificate'
        Properties:
          CertificateAuthorityArn: !Ref SubordinateCAOne
          CertificateSigningRequest: !GetAtt 
            - SubordinateCATwo
            - CertificateSigningRequest
          SigningAlgorithm: SHA256WITHRSA
          TemplateArn: 'arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen2/V1'
          Validity:
            Type: DAYS
            Value: 80
      SubordinateCATwoActivation:
        Type: 'AWS::ACMPCA::CertificateAuthorityActivation'
        Properties:
          CertificateAuthorityArn: !Ref SubordinateCATwo
          Certificate: !GetAtt 
            - SubordinateCATwoCACertificate
            - Certificate
          CertificateChain: !GetAtt 
            - SubordinateCAOneActivation
            - CompleteCertificateChain
      EndEntityCertificate:
        DependsOn: SubordinateCATwoActivation
        Type: 'AWS::ACMPCA::Certificate'
        Properties:
          CertificateAuthorityArn: !Ref SubordinateCATwo
          #CSRは適宜変更してください。(サンプルなので特にマスクしません)
          CertificateSigningRequest: !Join 
            - |+
     
            - - '-----BEGIN CERTIFICATE REQUEST-----'
              - MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDzANBgNV
              - BAcMBkxpbmRvbjEWMBQGA1UECgwNRGlnaUNlcnQgSW5jLjERMA8GA1UECwwIRGln
              - aUNlcnQxHTAbBgNVBAMMFGV4YW1wbGUuZGlnaWNlcnQuY29tMIIBIjANBgkqhkiG
              - 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8+To7d+2kPWeBv/orU3LVbJwDrSQbeKamCmo
              - wp5bqDxIwV20zqRb7APUOKYoVEFFOEQs6T6gImnIolhbiH6m4zgZ/CPvWBOkZc+c
              - 1Po2EmvBz+AD5sBdT5kzGQA6NbWyZGldxRthNLOs1efOhdnWFuhI162qmcflgpiI
              - WDuwq4C9f+YkeJhNn9dF5+owm8cOQmDrV8NNdiTqin8q3qYAHHJRW28glJUCZkTZ
              - wIaSR6crBQ8TbYNE0dc+Caa3DOIkz1EOsHWzTx+n0zKfqcbgXi4DJx+C1bjptYPR
              - BPZL8DAeWuA8ebudVT44yEp82G96/Ggcf7F33xMxe0yc+Xa6owIDAQABoAAwDQYJ
              - KoZIhvcNAQEFBQADggEBAB0kcrFccSmFDmxox0Ne01UIqSsDqHgL+XmHTXJwre6D
              - hJSZwbvEtOK0G3+dr4Fs11WuUNt5qcLsx5a8uk4G6AKHMzuhLsJ7XZjgmQXGECpY
              - Q4mC3yT3ZoCGpIXbw+iP3lmEEXgaQL0Tx5LFl/okKbKYwIqNiyKWOMj7ZR/wxWg/
              - ZDGRs55xuoeLDJ/ZRFf9bI+IaCUd1YrfYcHIl3G87Av+r49YVwqRDT0VDV7uLgqn
              - 29XI1PpVUNCPQGn9p/eX6Qo7vpDaPybRtA2R7XLKjQaF9oXWeCUqy1hvJac9QFO2
              - 97Ob1alpHPoZ7mWiEuJwjBPii6a9M9G30nUo39lBi1w=
              - '-----END CERTIFICATE REQUEST-----'
          SigningAlgorithm: SHA256WITHRSA
          Validity:
            Type: DAYS
            Value: 70
    

    やってみた

    上記のテンプレートをCFnに流します。

    マネージメントコンソールからACMのプライベートCAを見てみるとルートCAが1つ、下位CAが2つ作成されています。

    「アクション」から「CA証明書の取得」を選択すると証明書をエクスポートできます。

    まとめ

    CloudFormationを使用してプライベートCAの構築、CAのアクティベーション、プライベート証明書の発行(実際のエクスポートは手作業)まで簡単におこなうことができました。CAのみ単体で構築するケースは多くない印象で、実際には他のサービスや機能と組み合わせ使うことになると思いますが、そういった際の参考になれば幸いです。

    以上、大阪オフィスの林がお送りしました!