🚴🏻‍♀️

REST API の相互 TLS 認証をやる。

2023/05/20に公開

概要

REST API の相互 TLS 認証を勉強する為の記事、API GATEWAYでのクライアント認証をやりたい。

AWS資料

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/rest-api-mutual-tls.html
https://repost.aws/ja/knowledge-center/api-gateway-tls-certificate

ClassMethod資料

https://dev.classmethod.jp/articles/api-gateway-support-mutual-tls-auth/

やってみる

Cloud9での環境作成

まずは環境準備

.pyenvの設定

# git clone
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# bash_profileの編集
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

# bash_profileの読み込み
source ~/.bash_profile

# ライブラリのInstall
sudo yum -y update
sudo yum remove -y openssl-devel
sudo yum -y install gcc make patch zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel tk-devel libffi-devel xz-devel openssl11 openssl11-devel

# Install 5分程度要します
pyenv install 3.10.11

# Version切り替え
pyenv global 3.10.11

# 最新化後のVersion確認
python --version

Python仮想環境作成

# 仮想環境の作成
python -m venv .venv

# アクティベート
source .venv/bin/activate

AWS CLI最新化

# インストーラーをDownLoad
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# 解答
unzip awscliv2.zip

# 最新化
sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update

# ゴミ削除
rm -rf aws awscliv2.zip 

# 最新化後のVersion確認
aws --version

AWS SAM CLI の最新化

# githubよりインストーラーをDownLoad
wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip

# 解答
unzip aws-sam-cli-linux-x86_64.zip -d sam-installation

# 最新化
sudo ./sam-installation/install --update

# ゴミ削除
rm -rf aws-sam-cli-linux-x86_64.zip sam-installation

# 最新化後のVersion確認
sam --version

AWS SAMでHelloWorld作成

API GatewayとLambda作成

SAM実行

# APPの初期化
cd ~/environment/
sam init

# 選択肢
- AWS Quick Start Templates
- Hello World Example
- N
- python3.10
- Zip
- N
- N
- rest-api-tls

# Build
cd ~/environment/rest-api-tls
sam build

# Deploy
cd ~/environment/rest-api-tls
sam deploy --guided

# 選択肢
基本デフォルト`HelloWorldFunction may not have authorization defined, Is this okay? [y/N]`だけY

# Deploy中
Deploy this changeset? [y/N]: Y

HelloWorldApiの変数設定

API_ENDPOINT="https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/"
curl $API_ENDPOINT

{"message": "hello world"}という文字が出ればOK

ACM作成

前提

Route53上にドメインがあることが前提

ACMにリクエスト発行

aws acm request-certificate \
  --domain-name $SUB_DOMAIN \
  --validation-method DNS

ACMの画面コンソールでRoute53へレコード登録が出来る画面があるので、従う

API Gatewayでカスタムドメイン作成

# ACMのARN取得
CertificateArn=$(aws acm list-certificates \
  --query "CertificateSummaryList[?DomainName==\`$SUB_DOMAIN\`].CertificateArn" \
  --output text);echo $CertificateArn

# API ID取得
ApiId=$(aws apigateway get-rest-apis \
  --query "items[?name==\`rest-api-tls\`].id" \
  --output text);echo $ApiId

# カスタムドメイン作成
aws apigatewayv2 create-domain-name \
  --domain-name $SUB_DOMAIN \
  --domain-name-configurations CertificateArn=$CertificateArn

# カスタムドメインにAPIを紐づける(APIマッピング)
aws apigatewayv2 create-api-mapping \
  --domain-name $SUB_DOMAIN \
  --api-id $ApiId \
  --stage Prod

Route53でカスタムドメインをAレコードに登録

上述のACM設定が通るまで少々時間がかかるようです。

カスタムドメインでAPI CALL

# 変数設定
SUB_DOMAIN_API_ENDPOINT=https://$SUB_DOMAIN/hello
echo $SUB_DOMAIN_API_ENDPOINT

# カスタムドメインでAPI CALL
curl $SUB_DOMAIN_API_ENDPOINT

{"message": "hello world"}という文字が出ればOK

デフォルトのApi Gateway Endpointを潰す

# 無効化
aws apigateway update-rest-api \
  --rest-api-id $ApiId \
  --patch-operations op=replace,path=/disableExecuteApiEndpoint,value='True'

# Deploy
aws apigateway create-deployment \
  --rest-api-id $ApiId \
  --stage-name Prod

# デフォルトのApi CALL
API_ENDPOINT="https://jyl2n5wj7h.execute-api.ap-northeast-1.amazonaws.com/"
curl $API_ENDPOINT

{"message":"Forbidden"} であればOK

クライアント証明書

# ルートCAの秘密鍵 を生成します
openssl genrsa -out RootCA.key 4096

# 自己署名CA証明書 を生成します
openssl req -new -x509 -days 3650 -key RootCA.key -out RootCA.pem

# クライアント証明書のプライベートキー を生成します
openssl genrsa -out my_client.key 2048

# 証明書署名要求 (CSR) を生成します
openssl req -new -key my_client.key -out my_client.csr

# CA を使用してクライアント証明書に署名します
openssl x509 -req -in my_client.csr -CA RootCA.pem -CAkey RootCA.key -set_serial 01 -out my_client.pem -days 3650 -sha256

S3にCA証明書をUp

# S3作成(S3の名前は各自で変更)
aws s3 mb s3://rest-api-tls-shigeruoda-20230520

# S3に格納
aws s3 cp RootCA.pem s3://rest-api-tls-shigeruoda-20230520

クライアント証明書による認証を有効化

aws apigatewayv2 update-domain-name \
  --domain-name $SUB_DOMAIN \
  --domain-name-configurations CertificateArn=$CertificateArn \
  --mutual-tls-authentication TruststoreUri=s3://rest-api-tls-shigeruoda-20230520/RootCA.pem

更新まち。


ちょっと待機

カスタムドメインドメインでAPI CALL(失敗)

# カスタムドメインでAPI CALL
curl $SUB_DOMAIN_API_ENDPOINT

curl: (35) Recv failure: Connection reset by peer というエラー

カスタムドメインでAPI CALL(成功)

curl $SUB_DOMAIN_API_ENDPOINT --key my_client.key --cert my_client.pem

{"message": "hello world"}という文字が出ればOK

Discussion