ALBへのアクセスをCloudFront経由に制限する
以下のページで、CloudFrontのオリジンにALBを指定する構成をご紹介しました。
上記のページでもご説明しましたが、CloudFrontのオリジンにALBを指定したとしても、引き続きALBへの直接アクセスは可能です。
本ページでは、以下のページを参考にしつつ、カスタムヘッダーを設定して、ALBへの直接アクセスを制限する方法を確認します。
構築する環境
構成は冒頭でご紹介したページと同じです。
ただしALBへの直接アクセスを制限し、CloudFrontを経由するように強制します。
CloudFrontおよびALBに、カスタムヘッダーの設定を行います。
カスタムヘッダーに関する情報は、Secrets Managerに格納します。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/132
テンプレートファイルのポイント解説
本ページは、ALBへの直接アクセスを制限する方法を中心に取り上げます。
CloudFrontに関する基本的な事項は、以下のページをご確認ください。
ALBに関する基本的な事項は、以下のページをご確認ください。
(参考) Secrets Manager
Resources:
Secret:
Type: AWS::SecretsManager::Secret
Properties:
Description: test secret
GenerateSecretString:
ExcludeCharacters: ""
ExcludeLowercase: false
ExcludeNumbers: false
ExcludePunctuation: false
ExcludeUppercase: false
GenerateStringKey: !Ref CustomHeaderValueJsonKey
IncludeSpace: false
PasswordLength: !Ref CustomHeaderValueLength
RequireEachIncludedType: true
SecretStringTemplate: !Sub '{"${CustomHeaderNameJsonKey}": "${CustomHeaderName}", "${CustomHeaderValueJsonKey}": ""}'
KmsKeyId: alias/aws/secretsmanager
Name: !Ref Prefix
Code language: YAML (yaml)
ALBへの直接アクセスを制限するために、CloudFrontおよびALBにカスタムヘッダーに関する設定を行います。
このカスタムヘッダー情報の取り扱いについて、AWS公式では以下のように言及されています。
ヘッダー名と値が機密でない場合、他の HTTP クライアントは、Application Load Balancer に直接送信するリクエストにヘッダー名や値を含める可能性があります。これにより、リクエストをしていない時に、リクエストが CloudFront から送信されたかのように Application Load Balancer を動作させる可能性があります。これを防ぐためには、カスタムヘッダー名と値を機密にしておきます。
Application Load Balancers へのアクセスを制限する
上記に従い、今回はカスタムヘッダー情報をSecrets Managerに格納します。
今回生成するシークレット情報ですが、カスタムヘッダー名は「X-Custom-Header」と固定とします。
一方、カスタムヘッダー値は、シークレット作成時に、自動的にランダムパスワードを生成し、これを使用します。
Secrets Maangerを使用して、ランダムなパスワードを生成する方法に関しては、以下のページをご確認ください。
今回作成するシークレット情報ですが、JSON形式ですと、以下のような情報となります。
{“CustomHeaderName”: “X-Custom-Header”, “CustomHeaderValue”: “[random-string]”}
CloudFront
Resources:
Distribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
Cookies:
Forward: none
QueryString: false
TargetOriginId: !Ref ALBDNSName
ViewerProtocolPolicy: allow-all
DefaultTTL: !Ref CacheTTL
MaxTTL: !Ref CacheTTL
MinTTL: !Ref CacheTTL
Enabled: true
Origins:
- CustomOriginConfig:
OriginProtocolPolicy: http-only
DomainName: !Ref ALBDNSName
Id: !Ref ALBDNSName
OriginCustomHeaders:
- HeaderName: !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderNameJsonKey}}}"
HeaderValue: !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderValueJsonKey}}}"
PriceClass: PriceClass_All
Code language: YAML (yaml)
ポイントはOriginCustomHeadersプロパティです。
ここで設定したヘッダー情報が、CloudFront〜ALB間のトラフィックに追加されます。
先述のSecrets Managerの値を参照して、カスタムヘッダーを設定します。
具体的には、CloudFormationの動的な参照を使用します。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/dynamic-references.html
HeaderNameプロパティは、Secrets ManagerのJSONデータから、CustomHeaderNameの値を参照します。
HeaderValueプロパティは、Secrets ManagerのJSONデータから、CustomHeaderValueの値を参照します。
ALB
Resources:
ALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub "${Prefix}-ALB"
Scheme: internet-facing
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Type: application
ALBTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
Name: !Sub "${Prefix}-ALBTargetGroup"
Protocol: HTTP
Port: !Ref HTTPPort
HealthCheckProtocol: HTTP
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
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- FixedResponseConfig:
ContentType: text/plain
MessageBody: Access denied
StatusCode: 403
Type: fixed-response
LoadBalancerArn: !Ref ALB
Port: !Ref HTTPPort
Protocol: HTTP
ALBListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- TargetGroupArn: !Ref ALBTargetGroup
Type: forward
Conditions:
- Field: http-header
HttpHeaderConfig:
HttpHeaderName: !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderNameJsonKey}}}"
Values:
- !Sub "{{resolve:secretsmanager:${Secret}:SecretString:${CustomHeaderValueJsonKey}}}"
ListenerArn: !Ref ALBListener
Priority: 1
Code language: YAML (yaml)
ポイントは2点です。
1点目はALBリスナーのデフォルトアクションです。
冒頭でご紹介したページの構成ですと、デフォルトアクションとして、ALBターゲットグループへのルーティングするように設定していました。
今回の構成のデフォルトアクションでは、HTTPステータスコード403を返すように変更します。
2点目はリスナールールの追加です。
ALBターゲットグループへルーティングするルールを追加します。
Conditionプロパティで、このルールが適用される条件を設定します。
この条件はヘッダー情報に基づくものです。
着信したHTTPリクエストが、CloudFrontで設定したカスタムヘッダーを持つ場合に限り、ターゲットグループにルーティングされます。
チェックするカスタムヘッダー情報に関しては、CloudFrontと同様に、Secrets Managerの値を参照します。
2つのポイントをまとめますと、CloudFrontで設定したカスタムヘッダーを持つHTTPリクエストの場合は、ALBターゲットグループにルーティングされ、それ以外については403が返されます。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- Secrets Manager:fa-132
- インスタンス1:i-09f7807d448e1b62e
- インスタンス2:i-0e734e5fa1b1da141
- ALBのDNS名:fa-132-ALB-1742616783.ap-northeast-1.elb.amazonaws.com
- CloudFrontディストリビューションのDNS名:dq15nc7eow2lq.cloudfront.net
AWS Management Consoleからも、各リソースの作成状況を確認します。
Secrets Managerを確認します。
正常にシークレットが作成されています。
保存されている値を見ると、ヘッダー名とヘッダー値が保存されていることがわかります。
特にヘッダー値の方は、自動的にランダムな文字列が設定されています。
ALBを確認します。
正常にALBが作成されています。
ALBのターゲットグループを見ると、2つのインスタンスが登録されていることがわかります。
このALBのリスナールールを確認します。
2つのルールが設定されています。
最初のルールはターゲットグループへのルーティングに関するものです。
カスタムヘッダーの値が合致する場合に限り、ターゲットグループにルーティングされます。
この設定は、先述のSecrets Managerに保存した値に基づいて設定されています。
最後のルールは、上記のルールを満たさなかったトラフィック用のものです。
例えば直接ALBにアクセスした場合は、カスタムヘッダーの設定を持たないトラフィックとなりますので、ALBが403コードを返します。
CloudFrontを確認します。
正常にCloudFrontディストリビューションが作成されています。
ディストリビューションのオリジンに、先述のALBが指定されています。
このオリジンに関する設定を確認します。
カスタムヘッダーに関する項目を見ると、ALBリスナールールと同様の設定があります。
つまりこのCloudFrontディストリビューションを経由するトラフィックには、このカスタムヘッダーが付与されるということです。
動作確認
準備が整いましたので、CloudFrontにアクセスします。
$ curl https://dq15nc7eow2lq.cloudfront.net
instance-id: i-09f7807d448e1b62e
$ curl https://dq15nc7eow2lq.cloudfront.net
instance-id: i-0e734e5fa1b1da141
Code language: Bash (bash)
応答がありました。
ALB配下の2台のインスタンスにアクセスできています。
CloudFront経由でアクセスすると、途中でカスタムヘッダーが設定されるため、正常にALB配下のインスタンスにアクセスすることができました。
続いてALBに直接アクセスします。
$ curl http://fa-132-ALB-1742616783.ap-northeast-1.elb.amazonaws.com
Access denied
Code language: Shell Session (shell)
アクセスが拒否されました。
ALBに直接アクセスすると、カスタムヘッダーが設定されないため、ALBで403が返されました。
まとめ
カスタムヘッダーを設定して、ALBへの直接アクセスを制限する方法を確認しました。