概要
cloudfront等で、AWS WAFによってIPアクセス制限がかかっているリソースに対して、github actions hostedな環境からリクエス トを送りたい場合があると思います。
github actionsが利用するグローバルIPの範囲 は公開されていて、こちら全てをIP許可リストに追加することも可能ですが、保守面やセキュリティ観点としても推奨されるものではないと思います。
GitHub の IP アドレスはときどき変更されます。 IP アドレスによる許可はお勧めしません
GitHubのIPアドレスについて - GitHub Docs
そこで、実行中のgithub actions環境のIPを取得し、動的にIP許可リストに追加する方法を紹介します。
ちなみに、そもそもIPでなく専用のHTTPヘッダーを利用してWAFを突破するような方法も考えられますが、ここでは割愛します。
前提
以下はterraformの例ですが、WAF IPセットと許可ルールによるリソース構成になっている場合を想定します。
resource "aws_wafv2_ip_set" "my_project_github_actions" {
provider = aws.virginia
name = "github-actions"
scope = "CLOUDFRONT"
ip_address_version = "IPV4"
lifecycle {
ignore_changes = [
description,
addresses,
]
}
}
resource "aws_wafv2_web_acl" "my_project" {
provider = aws.virginia
name = "my-project-waf"
scope = "CLOUDFRONT"
~~中略~~
rule {
name = "allow-github-actions-ip"
priority = 1
action {
allow {
}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.my_project_github_actions.arn
}
}
}
~~中略~~
結果
~~ 中略 ~~
jobs :
sample :
runs-on : ubuntu-latest
timeout-minutes : 10
env :
WAF_IPSET_SCOPE : { YOUR_WAF_IPSET_SCOPE}
WAF_IPSET_REGION : { YOUR_WAF_IPSET_REGION}
WAF_IPSET_ID : { YOUR_WAF_IPSET_ID}
WAF_IPSET_NAME : { YOUR_WAF_IPSET_NAME}
permissions :
id-token : write
contents : read
steps :
- uses : actions/checkout@v3
- name : authenticate to aws
uses : aws-actions/configure-aws-credentials@v4
with :
aws-region : ${{ secrets.AWS_DEFAULT_REGION }}
role-to-assume : ${{ secrets.AWS_IAM_ROLE_ARN }}
- name : Get IP address
id : get-ip
run : echo "ip=$(curl -s https://checkip.amazonaws.com)" >> $GITHUB_OUTPUT
shell : bash
- name : Add IP address to ipset
shell : bash
run : |
current_ip=${{ steps.get-ip.outputs.ip }}/32
lock_token=$(aws wafv2 get-ip-set --scope $WAF_IPSET_SCOPE --region $WAF_IPSET_REGION --id $WAF_IPSET_ID --name $WAF_IPSET_NAME | jq -r '.LockToken' )
existing_ips=$(aws wafv2 get-ip-set --scope $WAF_IPSET_SCOPE --region $WAF_IPSET_REGION --id $WAF_IPSET_ID --name $WAF_IPSET_NAME | jq -r '.IPSet.Addresses[]' )
aws wafv2 update-ip-set --scope $WAF_IPSET_SCOPE --region $WAF_IPSET_REGION --id $WAF_IPSET_ID --name $WAF_IPSET_NAME --addresses $existing_ips $current_ip --lock-token $lock_token
sleep 10
- name : Delete IP address from ipset
if : always()
shell : bash
run : |
ip_to_remove=${{ steps.get-ip.outputs.ip }}/32
lock_token=$(aws wafv2 get-ip-set --scope $WAF_IPSET_SCOPE --region $WAF_IPSET_REGION --id $WAF_IPSET_ID --name $WAF_IPSET_NAME | jq -r '.LockToken' )
existing_ips=$(aws wafv2 get-ip-set --scope $WAF_IPSET_SCOPE --region $WAF_IPSET_REGION --id $WAF_IPSET_ID --name $WAF_IPSET_NAME | jq -r '.IPSet.Addresses[]' )
updated_ips=()
for ip in $existing_ips; do
if [ "$ip" != "$ip_to_remove" ] ; then
updated_ips+=("$ip")
fi
done
if [ ${#updated_ips[ @] } -eq 0 ] ; then
updated_ips_string='[]'
else
updated_ips_string=$(printf "%s " "${updated_ips[@]}" )
fi
aws wafv2 update-ip-set --scope $WAF_IPSET_SCOPE --region $WAF_IPSET_REGION --id $WAF_IPSET_ID --name $WAF_IPSET_NAME --addresses $updated_ips_string --lock-token $lock_token
設定値は以下です
・YOUR_WAF_IPSET_SCOPE: CLOUDFRONT か REGIONAL
・YOUR_WAF_IPSET_REGION: ipsetの存在するリージョン(CLOUDFRONTの場合、globalではなくus-east-1を指定する必要がありました)
・YOUR_WAF_IPSET_ID: 添付図参照
・YOUR_WAF_IPSET_NAME: 添付図参照
ipset
解説
・処理の流れは大きく以下になってます
実行環境のIP取得
1で取得したIPをipsetにinsert
IP制限環境へのリクエス ト
2で登録したIPをipsetから削除
・aws wafv2 では、v1やセキュリティグループの仕様とは違って、ipsetのリストへそのまま任意のIPを挿入/削除することはできないようでした。
(おそらく、AWS の内部的なデータ整合性の観点だと思われます)
そのため、一度入れ替え更新のようなコードになっています。
This operation completely replaces the mutable specifications that you already have for the IP set with the ones that you provide to this call.
To modify an IP set, do the following:
1. Retrieve it by calling GetIPSet
2. Update its settings as needed
3. Provide the complete IP set specification to this call
docs.aws.amazon.com