LoginSignup
1
2

More than 3 years have passed since last update.

CloudflareをALBの前に配置してAzureAD認証してみた

Posted at

CloudflareをALB(AWS)の前に配置して、CloudflareのAccessでAzureAD認証してみました。
どのクラウドでも実装できるはずなので、ちょっと認証かけたい時などなかなか便利です。

構成

cloudflare.png

  • Cloudflare以外からのアクセスは、ALBのセキュリティーグループでブロックします。
  • 自分のCloudflare以外のCloudflareからのアクセスは、Lambdaでjwtを検証してブロックします。

必要なもの

  • Cloudflareアカウント
  • AWSアカウント
  • ドメイン2個
    • ドメインA
    • ドメインB
  • ドメインBに対しAWS ACMで取得したワイルドカード証明書1個

設定

  1. Azure AD認証の対象リソースを作成する
  2. Cloudflare DNSを設定する
  3. Cloudflare Accessを設定する
  4. CloudfraleのIPアドレスをALBのセキュリティグループに設定する
  5. テストする

1. Azure AD認証の対象リソースを作成する

  1. AWS側でALBのターゲット用のLambdaを作成する
  2. ALBを作成する
    1. HTTPSのリスナーを作成しドメインBの証明書を紐づける
    2. ターゲットグループを作成して、Lambdaをターゲットに設定する
  3. Route53に、ALBのエイリアスレコードをドメインBのサブドメインとして設定する
  • jwtの検証は以下を参考にしました。
  • Lambda作成時のハマりポイント
    • Amazon Linux上でpip installしてLambdaのパッケージをzipで固めます。
    • Amazon Linuxの現在のyumリポジトリのPythonのバージョンは3.6なので、Lambda側も3.6に合わせます。
    • Lambdaのパッケージをzipで固める時、".libs_cffi_backend"配下も忘れずに含めます。
    • Cloudflareからのjwtを検証するためALBからのヘルスチェックは失敗するので、ヘルスチェックを外します。

以下Lambda内で指定している値は、Cloudflareの設定後に確認します。

Lambda内で指定している定数
CERTS_URL CloudflareのAccessのLogin Page Domain+"/cdn-cgi/access/certs"
AUDIENCE_TAG CloudflareのAccessのAccess PoliciesのAudience Tag
requirements.txt
pyjwt
cryptography
cffi
Lambda_function.py
import jwt
import json
import urllib.request

CERTS_URL = 'https://*******************/cdn-cgi/access/certs'
AUDIENCE_TAG = '**************************************'

def get_public_keys():
    headers = {
        'User-Agent': 'curl/7.61.1'
    }
    req = urllib.request.Request(CERTS_URL, headers=headers)
    with urllib.request.urlopen(req) as response:
        res = response.read()
    public_keys = []
    jwk_set = json.loads(res)

    for key_dict in jwk_set['keys']:
        public_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(key_dict))
        public_keys.append(public_key)
    return public_keys


def validate(header):
    is_valid = False
    token = ''
    if 'cf-access-jwt-assertion' in header:
        token = header['cf-access-jwt-assertion']
    else:
        return is_valid

    keys = get_public_keys()

    for key in keys:
        try:
            decoded_token = jwt.decode(token, key=key, audience=AUDIENCE_TAG)
            # print(decoded_token)
            is_valid = True
            break
        except Exception as e:
            print(e)
            pass
    return is_valid


def lambda_handler(event, context):
    is_valid = validate(event['headers'])

    if is_valid:
        res = {
            "isBase64Encoded": False,
            "statusCode": 200,
            "statusDescription": "200 OK",
            "headers": {
                "Set-cookie": "cookies",
                "Content-Type": "text/html"
            }
        }

        res['body'] = """<html>
        <head>
        <title>hello world</title>
        </head>
        <body>
        <h1>Hello World</h1>
        </body>
        </html>"""
    else:
        res = {
            "isBase64Encoded": False,
            "statusCode": 403,
            "statusDescription": "403"
        }

    return res

2. Cloudflare DNSを設定する

Cloudflare側でドメインAを登録します。

2_1_add_site.png

プランを選択します。

2_2_plan.png

ドメインAのレジストラで、Cloudfraleのネームサーバを設定します。
設定後、Cloudflareの画面に戻って、下記をクリックします。

2_3.png

Cloudflare側がドメインを認識するまで、数時間かかりました。

CNAMEレコードを登録します。

2_4_cname.png

項目
Type CNAME
Name ドメインA
Content ドメインBのサブドメイン(Route53に設定したALBのCNAME)
Proxy status Proxied

SSL/TLSの画面で、Fullを選択します。

2_5.png

ここまででの設定で、ドメインAにアクセスするとドメインBのサブドメインにproxyされてALBのターゲットのLambdaが呼ばれるようになります。

3. Cloudflare Accessを設定する

Cloudflare Accessを有効化します。

3_1.png

下記以外はデフォルトのまま設定します。

  • プランはAzure ADを利用するため、Access Premiumを選択

3_2.png

Login methodでAzure ADを選択します

3_4_loginmethod.png

Azure ADでアプリケーションを登録します。

4_1.png

クライアントシークレットを作成します。

4_2.png

パーミッションを設定します。

4_3.png

Application IDとDirectory IDを確認します。

4_5.png

Azure ADで設定した値をCloud flare側で設定します。

4_4.png

4. CloudfraleのIPアドレスをALBのセキュリティグループに設定する

下記IPアドレスをALBのセキュリティグループに設定します。
https://www.cloudflare.com/ips/

5. テストする

ドメインAに対しアクセスするとCloudflareの認証画面が表示されます。

5_1.png

Azure ADで認証して…

5_2.png

Lambdaで生成したページが表示されれば成功です!

5_3.png

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2