AWS Load Balancer Controller で ALB を IP 制限するときの注意点(source-ip の上限・優先度・反映中の 404)
EKS で動かしている API を、決まった接続元の IP からだけ使えるようにしたいことはありませんか?
ALB を AWS Load Balancer Controller で作っているなら、Ingress の annotation でリスナールールに接続元の IP の条件(source-ip)を付けられます。
設定そのものは数行足すだけですが、実際に入れてみると気を付けるところがいくつかありました。
結論から書くと、気を付けるところは次の 3 つです。
- source-ip は 1 つの条件に 3 つまでで、超える分はルールを分ける
- ルールの優先度は、Ingress の paths の並び順で決まる
- ルールの条件を書き換えると、反映中に一時的に 404 になる場合がある
3 つ目は、Load Balancer Controller のソースを読んで、どういうときに起きるのかを確かめました。
この記事では、それぞれの理由と、本番環境で 404 を出さずに反映した手順を紹介します。
確認した環境
- AWS Load Balancer Controller v2.17.1(EKS で動かしているもの)
- ソースは v2.17.1 と、執筆時点で最新の v3.6.2(2026 年 10 月 25 日公開)を読み比べた
この記事で触れる部分は、2 つのバージョンで同じ動きでした。
基本の設定: conditions と actions を組み合わせる
Load Balancer Controller では、alb.ingress.kubernetes.io/conditions.<名前> の annotation で、Ingress のパスにリスナールールの条件を足せます(公式ドキュメント)。
接続元の IP で絞るときは、source-ip の条件を使います。
転送先は alb.ingress.kubernetes.io/actions.<名前> に書き、paths の backend からは use-annotation で参照します。
例として、api.example.com の API を 3 つの IP からだけ使えるようにする設定です。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
alb.ingress.kubernetes.io/actions.allow-rule-1: >
{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"api-backend","ServicePort":"80"}]}}
alb.ingress.kubernetes.io/conditions.allow-rule-1: >
[{"Field":"source-ip","SourceIpConfig":{"Values":["203.0.113.10/32","203.0.113.11/32","203.0.113.12/32"]}}]
spec:
ingressClassName: alb
rules:
- host: api.example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: allow-rule-1
port:
name: use-annotationこれで、次の 3 つがそろったときに当たるリスナールールが 1 つできます。
- ホストが
api.example.com - パスが
/* - 接続元が 3 つの IP のどれか
許可していない IP からのアクセスは、どのルールにも当たらず、リスナーのデフォルトアクションに回ります。
私の環境では、許可していない IP から curl でアクセスして、デフォルトアクションの 404 が返ることを確かめました。
なお、source-ip の判定に使われるのは、ALB から見た接続元の IP です。
間にプロキシーがあるとプロキシーの IP で判定され、X-Forwarded-For ヘッダーの IP は見ません(AWS のドキュメント)。
注意点 1: source-ip は 1 つの条件に 3 つまで
許可したい IP が 4 つ以上あると、1 つのルールには入りません。
AWS のドキュメントには、条件に指定する値の数について、次の 2 つの決まりがあります。
- 1 つの条件に 3 つまで(up to three match evaluations per condition)
- 1 つのルール全体で 5 つまで(up to five match evaluations per rule)
Quotas のページにも「Condition Values per Rule」が 5 とあり、引き上げはできません。
ルール全体の上限 5 だけを見て、source-ip に 4 つ入れないように注意してください。
上の例では、ホストの 1 つとパスの 1 つも値として数えるので、source-ip に使えるのは残りの 3 つです。
ホストを指定しないルールでも、1 つの条件に 3 つまでの決まりがあるので、source-ip は 3 つまでです。
4 つ以上許可したいときは、同じパスのルールを分けて、IP を 3 つずつ入れます。
metadata:
annotations:
alb.ingress.kubernetes.io/actions.allow-rule-1: >
{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"api-backend","ServicePort":"80"}]}}
alb.ingress.kubernetes.io/conditions.allow-rule-1: >
[{"Field":"source-ip","SourceIpConfig":{"Values":["203.0.113.10/32","203.0.113.11/32","203.0.113.12/32"]}}]
alb.ingress.kubernetes.io/actions.allow-rule-2: >
{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"api-backend","ServicePort":"80"}]}}
alb.ingress.kubernetes.io/conditions.allow-rule-2: >
[{"Field":"source-ip","SourceIpConfig":{"Values":["198.51.100.20/32","198.51.100.21/32"]}}]
spec:
ingressClassName: alb
rules:
- host: api.example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: allow-rule-1
port:
name: use-annotation
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: allow-rule-2
port:
name: use-annotation同じパスのルールが並んでいても、条件が違えば問題ありません。
ALB はルールを優先度の順に評価し、条件に合ったルールで止まります。
ルールの数は、1 つの ALB に 100 個まで(引き上げ可能)なので、IP が多いとルールの数も増えていく点は覚えておくとよいです。
注意点 2: ルールの優先度は paths の並び順で決まる
ルールを分けると、次に気になるのが優先度(ルールを評価する順番)です。
Load Balancer Controller には、Ingress の中のルールの優先度を、番号で指定する設定がありません。
alb.ingress.kubernetes.io/group.order はありますが、これは複数の Ingress を 1 つの ALB にまとめるときの、Ingress 同士の順番です。
ソース(pkg/ingress/model_build_listener_rules.go)を読むと、優先度は次のように振られていました。
- Ingress の rules と paths を、上から順に並べる
- 並べた順に、1 から番号を振る
ただし、paths は pathType で並べ替えられてから番号が振られます。
- Exact のパスが先頭
- 次に Prefix のパスを、パスの長い順に並べる
- 最後に ImplementationSpecific(または pathType の指定なし)のパスを、書いた順のまま並べる
書いた順がそのまま優先度になるのは、ImplementationSpecific のパスだけです。
この記事の例は、すべて ImplementationSpecific で書いています。
注意点 3: 反映中に一時的に 404 になる場合がある
Ingress を変えると、Load Balancer Controller は ALB に設定済みのルールと Ingress から作ったルールを突き合わせます。
そのうえで、違うところだけを ALB に反映します。
ソース(pkg/deploy/elbv2/listener_rule_synthesizer.go)では、次の順番で処理していました。
- 内容(条件と転送先)がまったく同じルールは、番号だけを付け替える(SetRulePriorities をまとめて 1 回呼ぶ)
- 内容が違い、番号が同じルールは、その場で書き換える(ModifyRule)
- 新しく必要になったルールを作る(CreateRule)
- 要らなくなったルールを消す(DeleteRule)
1 の番号の付け替えは、2025 年 3 月の変更(#4039)で入り、v2.12.0 から含まれています。
それより前のバージョンは番号だけで突き合わせていました。
処理の順番も違い、要らないルールを先に消してから新しいルールを作り、最後に同じ番号のルールを書き換えていました。
v2.12.0 以降でも、ルールの内容が変わると 2 の「その場での書き換え」になり、番号の小さいルールから 1 つずつ書き換わります。
そのため、書き換えの途中や 3 で新しいルールができるまでの間に、許可したい IP がどのルールにも当たらない瞬間ができることがあります。
その間のアクセスは、デフォルトアクションの 404 になります。
私が気付いたのは、次の 2 つの場面です。
条件のないルールに、あとから条件を付けるとき
IP 制限を入れる前は、/* のルールに条件がなく、どこからでも使える状態でした。
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: api-backend
port:
number: 80これを、注意点 1 の 2 つのルールの形に 1 回で変えるとします。
番号 1 のルールは「内容が違い、番号が同じ」なので、その場で書き換わります。
書き換えたあとは、203.0.113.x の 3 つだけを許可するルールになります。
番号 2 のルールはまだないので、作られるまでの間、198.51.100.x からのアクセスは 404 になります。
IP を別のルールへ移すとき
前のルールの IP を後ろのルールへ移すと、両方のルールの内容が変わります。
どちらも「その場での書き換え」になり、番号の小さい前のルールから書き換わります。
前のルールから IP が消えてから、後ろのルールに IP が足されるまでの間、その IP はどのルールにも入っていません。
逆向き(後ろから前へ)なら隙間はできませんが、向きを気にしながら作業するより、移さないと決めてしまうほうが簡単です。
404 を出さずに IP 制限を入れるには: 2 段階に分けて反映する
開発環境では、数秒の 404 は許容して、1 回で反映しました。
本番環境は止めたくなかったので、次の 2 段階に分けました。
- 条件のない
/*のルールを先頭に残したまま、後ろに許可するルールを足す - 先頭のルールに source-ip の条件を付ける
1 段階目の paths は、次のようになります。
paths:
# 今までどおり条件なし。2 段階目で allow-rule-1 に変える
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: api-backend
port:
number: 80
# 1 段階目で足す
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: allow-rule-2
port:
name: use-annotation1 段階目では、既存のルールは内容も番号も変わらず、新しいルールが後ろに作られるだけです。
すべてのアクセスが先頭のルールに当たるので、この時点ではまだ制限はかかっていません。
2 段階目で先頭のルールを allow-rule-1 に変えると、注意点 1 の形になります。
このときの変更は先頭のルールの書き換え 1 回だけで、ほかの許可するルールはすでにあるので、隙間はできません。
本番環境の反映では、許可した接続元からのアクセスが 404 になることはありませんでした。
IP を変えるときの決まりを書いておく
IP 制限は、入れたあとも IP の追加や削除が続きます。
そこで、Ingress の YAML のコメントに、次の決まりを書いておきました。
- 既存の IP を別のルールへ移さない
- IP を足すときは、末尾のルールに足すか、末尾にルールを増やす
- IP を消しても、空いたところを詰めない
- 変更の多い接続元のルールほど、paths の後ろに置く
1 つ目は、上の「IP を別のルールへ移すとき」を避けるためです。
2〜4 つ目は、v2.12.0 以降なら番号の付け替えで済むので、必ず守らないといけないわけではありません。
それでも、変更のたびに差分が小さくなり、どのルールが書き換わるのかを読みやすくなります。
v2.11 以前のバージョンでは、途中にルールを足したり消したりすると後ろのルールがすべて「その場での書き換え」になります。
そのため、この決まりがそのまま効きます。
まとめ
- source-ip は 1 つの条件に 3 つまでで、ルール全体の 5 つとは別の決まり
- 優先度は paths の順に 1 から振られ、番号は指定できない(pathType による並べ替えもある)
- 内容が変わるルールは、反映中に一時的に 404 になる場合がある
- 条件のないルールから切り替えるときは、2 段階に分けると隙間ができない
IP 制限は入れたあとも IP の変更が続くので、最初に変更の決まりを決めておくと安心です。
