AWS

自己証明書でALB〜EC2間もSSL化する

スポンサーリンク
自己証明書でALB〜EC2間もSSL化する AWS
スポンサーリンク
スポンサーリンク

インターネット〜ALB間だけでなく、ALB〜EC2間もSSL化する構成

以下のページで、ACM証明書を使用して、インターネットからALBまでの通信をSSL化する構成をご紹介しました。

ただし上記の構成では、ALBまでの通信はHTTPSですが、ALBからEC2インスタンスまでの通信はHTTPとなります。そこで今回は、自己証明書を作成して、クライアント〜インスタンス間の全ての通信をSSL化することを目標とします。

構築する環境

Amazon.co.jp: AWS認定資格試験テキスト AWS認定ソリューションアーキテクト - アソシエイト 改訂第2版 : NRIネットコム株式会社, 佐々木 拓郎, 林 晋一郎, 金澤 圭: 本
Amazon.co.jp: AWS認定資格試験テキスト AWS認定ソリューションアーキテクト - アソシエイト 改訂第2版 : NRIネットコム株式会社, 佐々木 拓郎, 林 晋一郎, 金澤 圭: 本
Diagram of on ssl between ALB and EC2 using self-signed certificate.

基本的な構成は、先述ご紹介したページと同一です。今回はSSMドキュメント(AWS-ApplyAnsiblePlaybooks)を実行して、EC2インスタンスで自己証明書を作成します。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。以下のURLにCloudFormationテンプレートを配置してます。

awstut-fa/024 at main · awstut-an-r/awstut-fa
Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

テンプレートファイルのポイント解説

本ページでは、ALBのHTTPS通信への対応方法や、EC2インスタンスの自己証明書の作成方法に関して解説します。プライベートサブネット内のEC2をALBにアタッチする方法や、Route 53の設定方法、ACM証明書に関しては、以下のページをご確認ください。

ALBターゲットグループで、インスタンスへの通信はHTTPSに設定する

fa-024-alb.yamlでALB関係のリソースを定義しています。ポイントはALBターゲットグループです。

Resources: ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: VpcId: !Ref VPC Name: !Sub ${Prefix}-ALBTargetGroup Protocol: HTTPS Port: !Ref HTTPSPort HealthCheckProtocol: HTTPS HealthCheckPath: / HealthCheckPort: traffic-port HealthyThresholdCount: !Ref HealthyThresholdCount UnhealthyThresholdCount: !Ref UnhealthyThresholdCount HealthCheckTimeoutSeconds: !Ref HealthCheckTimeoutSeconds HealthCheckIntervalSeconds: !Ref HealthCheckIntervalSeconds Matcher: HttpCode: !Ref HttpCode Targets: - Id: !Ref Instance1 - Id: !Ref Instance2
Code language: YAML (yaml)

3つのパラメータに注目です。1つ目はProtocolプロパティです。ターゲットであるインスタンスに通信するプロトコルを設定します。今回は「HTTPS」を設定します。2つ目はPortプロパティです。ターゲットが待ち受けているポート番号を設定します。今回はデフォルトの「443」を設定します。3つ目はHealthCheckProtocolプロパティです。ヘルスチェックとして、ALBがインスタンスにアクセスする際のプロトコルを設定します。こちらも「HTTPS」を指定します。

インスタンスのセキュリティグループでHTTPSを許可する

続いてfa-024-vpc.yamlで定義されている、インスタンスに適用するセキュリティグループを確認します。

Resources: InstanceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub "${Prefix}-InstanceSecurityGroup" GroupDescription: Allow HTTPS from ALBSecurityGroup. VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: !Ref HTTPSPort ToPort: !Ref HTTPSPort SourceSecurityGroupId: !Ref ALBSecurityGroup
Code language: YAML (yaml)

FromPortおよびToPortプロパティで、許可するポート番号を指定します。両プロパティに「443」を設定することで、HTTPS通信のみを許可します。

Ansibleで自己証明書作成を作成する

SSM関連付け

最後にfa-024-ssm.yamlで定義されている、SSM関係のリソースを確認します。

2つのインスタンスに対して、統一的に自己証明書を作成する手順を実行するために、Ansibleを使用します。今回はSSMドキュメントAWS-ApplyAnsiblePlaybooksを使用します。注意すべき点は、インスタンスがプライベートサブネット内に設置されているという点です。そのためVPCエンドポイントを経由してSSM・S3にアクセスすることで、同ドキュメントを実行します。詳細については、以下のページをご確認ください。

Ansible Playbook

Ansibleで実行するPlaybookの中身を確認します。

- hosts: all gather_facts: no become: yes tasks: - name: update yum yum: name=* - name: install the latest version of Apache yum: name=httpd state=latest - name: install the latest version of openssl yum: name=openssl state=latest - name: install the latest version of mod_ssl yum: name=mod_ssl state=latest - name: copy openssl.cnf copy: src: ./openssl.cnf dest: /etc/pki/tls/openssl.cnf owner: root group: root mode: '0644' - name: copy ssl.conf copy: src: ./ssl.conf dest: /etc/httpd/conf.d/ssl.conf owner: root group: root mode: '0644' - name: generate private key shell: openssl genrsa > server.key - name: generate public key shell: openssl req -new -batch -key server.key > server.csr - name: generate crt shell: openssl x509 -req -signkey server.key < server.csr > server.crt - name: copy private key shell: cp -a ./server.key /etc/pki/tls/private/ - name: copy crt shell: cp -a ./server.crt /etc/pki/tls/certs/ - name: start and enable Apache service: name=httpd state=started enabled=yes - name: make index.html shell: ec2-metadata -i > /var/www/html/index.html
Code language: YAML (yaml)

ApacheおよびSSL化のために必要なパッケージ(openssl, mod_ssl)をインストール後、2つの設定ファイル(openssl.cnf, ssl.conf)を、用意したファイルと置き換えます。以降の手順では、自己証明書を使用するための手順です。具体的には、秘密鍵、公開鍵、証明書を作成後、秘密鍵と証明書を所定の位置に設置します。最後にApacheを起動後、index.htmlに自身のインスタンスIDを書き込みます。なおコマンドはこのページを参考に設定しました。

(参考)openssl.cnf

openssl.cnfの変更点をご説明します。公開鍵を作成する上で、コマンドをバッチモードで実行するために、各パラメータのデフォルト値を以下の通りに変更しました。

  • countryName_default = JP
  • stateOrProvinceName_default = Tokyo
  • localityName_default = Hogehoge
  • 0.organizationName_default = HugaHuga
  • organizationalUnitName_default = Piyopiyo
  • commonName_default = spamspam
  • emailAddress_default = mail.example.com

(参考)ssl.conf

ssl.confの変更点をご説明します。

証明書と秘密鍵の設置場所を以下の通りに変更しました。

  • SSLCertificateFile /etc/pki/tls/certs/server.crt
  • SSLCertificateKeyFile /etc/pki/tls/private/server.key

なおこちらの設定も、このページを参考に設定しました。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

Ansible Playbookの準備

CloudFormationスタックを作成する前に、Ansibleの準備を行います。具体的にはPlaybookをZip化し、S3バケットに設置します。

$ zip -r playbook.zip * adding: openssl.cnf (deflated 67%) adding: playbook.yml (deflated 67%) adding: ssl.conf (deflated 59%) $ aws s3 cp playbook.zip s3://[bucket-name]/ upload: ./playbook.zip to s3://[bucket-name]/playbook.zip
Code language: Bash (bash)

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • Instance1:i-06b5fa80e358558a2
  • Instance2:i-0b0b10fbc49e33809
  • ALB:fa-024-ALB
  • Route 53のレコード:awstut.net

AWS Management Consoleからも、リソースの作成状況を確認します。まずALBターゲットグループを確認します。

It is configured to communicate via HTTPS to the ALB target group.

ターゲットグループに、2つのインスタンスが登録されていることがわかります。またインスタンスに対して、443番ポートにHTTPSで通信する設定になっていることもわかります。次にSSMステートマネージャーの実行状況も確認します。

The SSM Association has been created successfully.

2つのSSM関連付けの作成が成功していることがわかります。このことからAnsibleが正常に実行されたことがわかります。

ALBにアクセスする

準備が整いましたので、ブラウザから、HTTPSで独自ドメインにアクセスします。

Accessing EC2 instances via ALB with end-to-end SSL-encrypted communication 1.
Accessing EC2 instances via ALB with end-to-end SSL-encrypted communication 2.

ALBにアクセスすることができました。以上より、クライアント〜ALB間だけでなく、ALB〜インスタンス間もSSL化することができました。

(参考) Ansible実行ログ

参考として、Instance1におけるAnsible実行ログの抜粋を置いておきます。

Running Ansible in /var/lib/amazon/ssm/i-06b5fa80e358558a2/document/orchestration/a3e0b63e-23f6-4e80-bfe3-4c73c83f6ab6/downloads Archive: ./playbook.zip inflating: openssl.cnf inflating: playbook.yml inflating: ssl.conf Using /etc/ansible/ansible.cfg as config file PLAY [all] ********************************************************************* TASK [update yum] ************************************************************** ok: ... TASK [install the latest version of Apache] ************************************ changed: ... TASK [install the latest version of openssl] *********************************** ok: ... TASK [install the latest version of mod_ssl] *********************************** changed: ... TASK [copy openssl.cnf] ******************************************************** changed: [localhost] => {"changed": true, "checksum": "870dcd50252d8aa8e1aa6392ce29a987480b337c", "dest": "/etc/pki/tls/openssl.cnf", "gid": 0, "group": "root", "md5sum": "3aa020ec74b4fb8be0aaf8746a489215", "mode": "0644", "owner": "root", "size": 11173, "src": "/root/.ansible/tmp/ansible-tmp-1644752856.2-2777-102212935013649/source", "state": "file", "uid": 0} TASK [copy ssl.conf] *********************************************************** changed: [localhost] => {"changed": true, "checksum": "10d92760527eaa77206766f62f47cb1346121434", "dest": "/etc/httpd/conf.d/ssl.conf", "gid": 0, "group": "root", "md5sum": "1747532281ea14600da458ef529f37da", "mode": "0644", "owner": "root", "size": 9544, "src": "/root/.ansible/tmp/ansible-tmp-1644752857.31-2820-240351648915287/source", "state": "file", "uid": 0} TASK [generate private key] **************************************************** changed: [localhost] => {"changed": true, "cmd": "openssl genrsa > server.key", "delta": "0:00:00.117549", "end": "2022-02-13 11:47:38.683733", "rc": 0, "start": "2022-02-13 11:47:38.566184", "stderr": "Generating RSA private key, 2048 bit long, ... TASK [generate public key] ***************************************************** changed: [localhost] => {"changed": true, "cmd": "openssl req -new -batch -key server.key > server.csr", "delta": "0:00:00.026476", "end": "2022-02-13 11:47:39.110980", "rc": 0, "start": "2022-02-13 11:47:39.084504", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} TASK [generate crt] ************************************************************ changed: [localhost] => {"changed": true, "cmd": "openssl x509 -req -signkey server.key < server.csr > server.crt", "delta": "0:00:00.038384", "end": "2022-02-13 11:47:39.541607", "rc": 0, "start": "2022-02-13 11:47:39.503223", ... TASK [copy private key] ******************************************************** changed: [localhost] => {"changed": true, "cmd": "cp -a ./server.key /etc/pki/tls/private/", "delta": "0:00:00.018995", "end": "2022-02-13 11:47:39.959631", "rc": 0, "start": "2022-02-13 11:47:39.940636", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} TASK [copy crt] **************************************************************** changed: [localhost] => {"changed": true, "cmd": "cp -a ./server.crt /etc/pki/tls/certs/", "delta": "0:00:00.018371", "end": "2022-02-13 11:47:40.383606", "rc": 0, "start": "2022-02-13 11:47:40.365235", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} TASK [start and enable Apache] ************************************************* changed: ... TASK [make index.html] ********************************************************* changed: ... PLAY RECAP ********************************************************************* localhost : ok=13 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Code language: plaintext (plaintext)

まとめ

自己証明書を作成し、ALB〜インスタンス間の通信もSSL化する方法を確認しました。

証明書の作成の手続きをAnsible Playbook化することで、2つのインスタンスに統一して実行することができました。

タイトルとURLをコピーしました