継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

CloudFront のセキュリティヘッダーの設定を試した

タダです.

CloudFront でホスティングしているサイトのレスポンスにセキュリティヘッダーをつける対応を行ったので,その備忘録を残しておきます.

CloudFront のセキュリティヘッダーとは

CloudFront では以下のようなセキュリティヘッダーを加えてレスポンスができる機能です.この機能が登場以前は Lambda@Edge などでレスポンスヘッダーを追加して上げる必要があったと思いますが,CloudFront の機能だけでレスポンスヘッダーへの追加が完結するのはいいことですね.

  • HTTP Strict Transport Security (HSTS)
  • X-XSS-Protection
  • X-Content-Type-Options
  • X-Frame-Options
  • Referrer-Policy
  • Content-Security-Policy

aws.amazon.com

セキュリティヘッダーを追加してみる

それでは CloudFront - S3 でコンテンツを返す設定をしているディストリビューションにセキュリティヘッダーを追加してみます.この記事では HSTS のみを有効化し,前後のレスポンスヘッダーの状態を確認してみます.まずは設定変更前が以下のような状態で当然ですが,セキュリティヘッダーが返ってきません.

セキュリティヘッダー追加前

$ curl -I https://www.hoge.com
HTTP/2 200
content-type: text/html
content-length: 8
date: Sat, 03 Dec 2022 07:43:12 GMT
last-modified: Sat, 03 Dec 2022 07:33:59 GMT
etag: "1313058fad6daf581fdcfea2e76ac3b1"
accept-ranges: bytes
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 964dcea2ce9513bdb853e662b2030b0a.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT51-P2
x-amz-cf-id: LBSFP4KsgFReRH730JOKqCvdF00yFzs8Oc6cN9Z6NOwvAriMYI8bDQ==

セキュリティヘッダーのポリシー作成と適用

セキュリティヘッダーを追加してみます.CloudFront > ポリシー > レスポンスヘッダー の順に遷移してレスポンスヘッダーポリシーを作成から作っていきます.ご覧のようにバーを有効化してセキュリティヘッダーの最大経過時間を指定し保存すれば,ポリシー作成は完了です.

次にポリシーをディストリビューションに適用していきます.この後,再度サイトにアクセスすると,strict-transport-security という HSTS のヘッダーが返ってきました.

$ curl -I https://www.hoge.com
HTTP/2 200
content-type: text/html
content-length: 8
date: Sat, 03 Dec 2022 07:53:18 GMT
last-modified: Sat, 03 Dec 2022 07:33:59 GMT
etag: "1313058fad6daf581fdcfea2e76ac3b1"
accept-ranges: bytes
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 d063c80c78a8368d53c4a98089af352a.cloudfront.net (CloudFront)
x-amz-cf-pop: KIX56-C2
x-amz-cf-id: nF3_Nk4D25L5-t2FzjWLKnqFirsq6419T_DekwhFbp7ucpmY2maqJw==
strict-transport-security: max-age=600

まとめ

CloudFront のセキュリティヘッダー機能を使ったのでまとめました.有効化が非常に簡単で,使う機会があればサクッと試せる機能だと思いました.

別アカウントで取得した ACM の DNS 認証を Route53 で行う

タダです.

Route53 でレコードを管理している AWS アカウント Aと ACM を発行して ALB や CloudFront に使う AWS アカウント B が別れている場合,ACMDNS 認証で証明書を有効化できるかというのを確認したので備忘録として残しておきます.

ACM の発行の作業

まず,アカウント B が ACM を発行します.アカウント A で管理しているホストゾーンのドメインワイルドカード証明書を取ろうとしている例になります.Route53 に登録するレコードを確認してメモしておきます.

Route53 でレコードの登録

アカウント A でレコードを登録していきます.メモをしておいて CNAME 名と値をセットします.赤枠で囲んだのがそのレコードです.

ACM の有効化状況確認

アカウント B で ACM の有効化状況を確認します.有効化完了しておりました.

まとめ

今回は基本的にできると思っていたが,検証してみたことがなかったアカウント跨ぎでの ACM DNS 認証を試したのでまとめました.

EventBridge のテストイベントを試すコマンドを使ってみた

タダです.

EventBridge をスケジューラーとしてばかり使ってきたのですが,カスタムイベントパターンを使う機会がでてきました.調べたところ EventBridge にはテストイベントを使えるから試してみたので備忘録で小ネタとして残します.

テストイベントコマンドについて

test-event-pattern コマンドです.これを使ってイベントと一致するかどうかをテストします.イベントパターンがあっていれば true があり,イベントパターンが異なっていると false が変えるためこの辺でテストが可能です.

成功パターン

aws events test-event-pattern --event-pattern "{\"source\":[\"com.mycompany.myapp\"]}" --event "{\"id\":\"1\",\"source\":\"com.mycompany.myapp\",\"detail-type\":\"myDetailType\",\"account\":\"123456789012\",\"region\":\"us-east-1\",\"time\":\"2022-04-11T20:11:04Z\"}"
{
    "Result": true
}

失敗パターン(意図的にイベントソースを aws.ec2 で指定)

aws events test-event-pattern --event-pattern "{\"source\":[\"aws.ec2\"]}" --event "{\"id\":\"1\",\"source\":\"com.mycompany.myapp\",\"detail-type\":\"myDetailType\",\"account\":\"123456789012\",\"region\":\"us-east-1\",\"time\":\"2022-04-11T20:11:04Z\"}"
{
    "Result": false
}

docs.aws.amazon.com

まとめ

簡単ですが,test-event-pattern コマンドのメモを残しました.

MySQL の構成管理を Terraform で行う

タダです.

RDS MySQL でのユーザーやデーターベース管理を Terraform でやりたいと思い,MySQL Provider を使ってみたのでこの記事にまとめていきます.

MySQL Provider について

まず MySQL Providerですが,公式はリポジトリアーカイブになっています.現状開発が行われているのがコミュニティの下記の Provider になります.そのため,この記事では下記のものを使って検証しています.

registry.terraform.io

Provider の設定

MySQL Provider を使用するための設定例に則って Aurora のデータベースを作ることをやってみます.

terraform {
  required_version = "1.3.4"
  required_providers {
    mysql = {
      source  = "petoju/mysql"
      version = "3.0.23"
    }
  }
}
provider "mysql" {
  endpoint              = "test.cluster-c5fumzy2ihj5.ap-northeast-1.rds.amazonaws.com"
  username              = var.terraform_exec_user
  password              = var.password
}

terraform plan/apply の実行

RDS は一般的にプライベートサブネットに配置されているため,terraform planterraform apply をローカルから実行してもネットワーク的に到達しないため AWS のネットワーク内で実行する必要がありますが,今回は GitHub Actions -> CodeBuild を実行して Terraform の実行をしてみます.GitHub Actions -> CodeBuild のキックは aws-actions/aws-codebuild-run-build を使って行いました.

Terraform の定義

データベースの定義は次のようにしてます.本当にシンプルなコードです.

resource "mysql_database" "app" {
  name = "codebuild_terraform_db"
}

registry.terraform.io

GitHub Actions の定義

GitHub Actions の定義は次のようにしています.GitHub Actions -> CodeBuild を実行する権限は README にあるものを設定して OIDC 経由で実行するようにしてます.加えてネットワーク周りを整えてあげて terraform planterraform apply してみます.

name: Run Codebuild

on:
  push:
    branches:
      - main

permissions:
  id-token: write
  contents: read

env:
  REGION: ap-northeast-1
  PROJECT_NAME: gha-codebuild-test

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: arn:aws:iam::11111111111111:role/gha-codebuild-run-role
        aws-region: ${{ env.REGION }}
    - name: Run CodeBuild
      uses: aws-actions/aws-codebuild-run-build@v1
      with:
        project-name: ${{ env.PROJECT_NAME }}

CodeBuild の実行結果

CodeBuild の実行結果は以下のような形で確認できたのと,対象の Aurora にもデータベースができてることを確認できました.

CodeBuild の実行結果

[Container] 2022/11/07 02:48:15 Running command cd terraform
terraform init
terraform plan -var 'password=$TF_ENV_password'


Initializing the backend...

Initializing provider plugins...
- Finding petoju/mysql versions matching "3.0.23"...
- Installing petoju/mysql v3.0.23...
- Installed petoju/mysql v3.0.23 (self-signed, key ID 298A405CE1C450D2)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # mysql_database.app will be created
  + resource "mysql_database" "app" {
      + default_character_set = "utf8mb4"
      + default_collation     = "utf8mb4_general_ci"
      + id                    = (known after apply)
      + name                  = "codebuild_terraform_db"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

[Container] 2022/11/07 02:48:19 Phase complete: BUILD State: SUCCEEDED

MySQL での確認結果

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 23
Server version: 8.0.23 Source distribution

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+------------------------+
| Database               |
+------------------------+
| codebuild_terraform_db |
| information_schema     |
| mysql                  |
| performance_schema     |
| sys                    |
+------------------------+
5 rows in set (0.00 sec)

まとめ

MySQL Provider を使って構成管理にコミュニティでメンテナンスされているものを使ってみたので記事にまとめました.

RDS の IAM 認証で使うトークンにホスト名を指定できるか?

タダです.

RDS の IAM 認証をする時に言われてみれば試したことなかったことを経験したので備忘録でまとめます.

sadayoshi-tada.hatenablog.com sadayoshi-tada.hatenablog.com

概要

Aurora Serverless に接続するために IAM 認証を使うことにしたのですが,接続時に下記のように aws rds generate-db-auth-tokenトークンを取得する処理があります.その際に --hostname で指定するのがこれまでは Aurora Serverless で生成されるエンドポイントを指定していました.ここに指定するのを Route53 に登録している CNAME レコードを指定するとどうなるのかを経験したのでまとめます.

mysql -h [Aurora Serveless V2 エンドポイント] -u [DB ユーザー名] -p`aws rds generate-db-auth-token --hostname [Aurora Serveless V2 エンドポイント] --port 3306 --username [DB ユーザ名] --region ap-northeast-1` --enable-cleartext-plugin 

事前準備

予め Aurora Serverless に加え接続用 EC2 と Route53 のレコードを用意して CNAME で名前解決できるようになった状態にしました.

$dig write-db.hoge.com                                                                                                                                                          

; <<>> DiG 9.10.6 <<>> write-db.hoge.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54943
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;write-db.hogecom.    IN  A

;; ANSWER SECTION:
write-db.hoge.com. 377    IN  CNAME   test.cluster-rtyuikfghj.ap-northeast-1.rds.amazonaws.com.
test.cluster-rtyuikfghj.ap-northeast-1.rds.amazonaws.com. 15 IN CNAME test-instance-1.rtyuikfghj.ap-northeast-1.rds.amazonaws.com.
test-instance-1.rtyuikfghj.ap-northeast-1.rds.amazonaws.com. 15 IN A 10.123.456.789

$dig read-db.hoge.com                                                                                                                                                           ~

; <<>> DiG 9.10.6 <<>> read-db.hoge.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38417
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;read-db.hoge.com.    IN  A

;; ANSWER SECTION:
read-db.hoge.com. 377 IN  CNAME   test.cluster-ro-rtyuikfghj.ap-northeast-1.rds.amazonaws.com.
test.cluster-ro-rtyuikfghj.ap-northeast-1.rds.amazonaws.com. 15 IN CNAME test-instance-1.rtyuikfghj.ap-northeast-1.rds.amazonaws.com.
test-instance-1.rtyuikfghj.ap-northeast-1.rds.amazonaws.com. 15 IN A 10.123.456.789

試した接続方法

次の3つの方法を試しました.

  1. トークン取得ではエンドポイント名を指定し,MySQL 接続時のホスト名は CNAME レコード
  2. トークン取得も MySQL 接続時のホスト名も CNAME レコード
  3. トークン取得時は CNAME レコードにし,MySQL 接続時のホスト名はエンドポイント名

なお,過去の記事ではトークン取得も MySQL 接続時のホスト名もエンドポイント名を指定しており,下記のように接続成功しています.

$ mysql -h test.cluster-rtyuikfghj.ap-northeast-1.rds.amazonaws.com -u iam_test -p`aws rds generate-db-auth-token --hostname test.cluster-rtyuikfghj.ap-northeast-1.rds.amazonaws.com --port 3306 --username iam_test --region ap-northeast-1` --enable-cleartext-plugin
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 35
Server version: 8.0.23 Source distribution

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

トークン取得ではエンドポイント名を指定し,MySQL 接続時のホスト名は CNAME レコード

トークン取得ではエンドポイント名を指定し,MySQL 接続時のホスト名は CNAME レコードの場合ですが,これは成功します.

$ mysql -h write-db.hoge.com -u iam_test -p`aws rds generate-db-auth-token --hostname test.cluster-rtyuikfghj.ap-northeast-1.rds.amazonaws.com --port 3306 --username iam_test --region ap-northeast-1` --enable-cleartext-plugin
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 37
Server version: 8.0.23 Source distribution

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

トークン取得も MySQL 接続時のホスト名も CNAME レコード

次にトークン取得も MySQL 接続時のホスト名も CNAME レコードを指定した場合,こちらは失敗します.

$ mysql -h write-db.hoge.com -u iam_test -p`aws rds generate-db-auth-token --hostname write-db.hoge.com --port 3306 --username iam_test --region ap-northeast-1` --enable-cleartext-plugin
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'iam_test'@'10.123.456.789' (using password: YES)

トークン取得時は CNAME レコードにし,MySQL 接続時のホスト名はエンドポイント名

最後にトークン取得時は CNAME レコードにし,MySQL 接続時のホスト名はエンドポイント名を指定した場合も失敗します.

$ mysql -h test.cluster-rtyuikfghj.ap-northeast-1.rds.amazonaws.com -u iam_test -p`aws rds generate-db-auth-token --hostname write-db.hoge.com --port 3306 --username iam_test --region ap-northeast-1` --enable-cleartext-plugin
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'iam_test'@'10.123.456.789' (using password: YES)

まとめ

以上のようにドメインを接続時に指定する場合は,トークン取得ではエンドポイント名を指定し,MySQL 接続時のホスト名は CNAME レコードというパターンが成功しています.ドキュメントを見ると The hostname of the database to connect to と指定が --hostname の箇所があったので勘違いしてたのですが,調べてみないとわからかったことなので備忘録として残しておきます.

awscli.amazonaws.com