LoginSignup
0
0

[Ansible]Cloudflare Zero Trust配下のAAP設定をGitLabで管理②~Cloudflare・GitLab設定~

Last updated at Posted at 2023-08-23

本記事は以下2部構成で作成しています。

[Ansible]Cloudflare Zero Trust配下のAAP設定をGitLabで管理①~Playbook作成~
[Ansible]Cloudflare Zero Trust配下のAAP設定をGitLabで管理②~Cloudflare・GitLab設定~(本記事)

はじめに

全体の構成は以下の通りです。
詳細は前記事を参照ください。

image.png

前記事では、AAPでWebhookを受け取れるようにしました。
本記事では、Cloudflare Zero Trust(以降Cloudflareという)経由でGitLab RunnerからWebhookを送れるようにします。(図の②、③)

構築

②CloudflareでGitLab通信のみ通信許可

まずは、外部からの通信をCloudflareで制御してGitLab Runnerからの通信のみAAPへ通すようにします。

Service Token作成

Cloudflareでは、原則としてWebアクセスはSAMLなどのユーザ認証に成功したユーザアクセスのみがポリシー評価対象となり、それ以外はポリシー評価すらされません。
そのため、今までのような特定IPアドレスレンジは問答無用で許可というような制御は出来ません。

しかし、それではユーザ認証ができないサービスアプリケーションから利用できないため、Service Tokenという仕組みをが用意されています。

これは、Cloudflareがサービス用に発行したID(CF-Access-Client-Id)とシークレット(CF-Access-Client-Secret)をヘッダーに加えることでどのアプリケーションからのアクセスかを識別できるようにするものです。
具体的には上記ヘッダーによってJWT生成してCookieに保存してそちらで識別します。

Cloudflare Zero Trustダッシュボードより、Access > Service Auth > Service Tokensにアクセスしてトークンを作成します。

作成すると以下のようにIDとシークレットが表示されます。
シークレットはこのタイミングでしか表示されないのでコピー必須です。

image.png

アプリケーションポリシー設定

先程作成したService Tokenを使った通信を許可するようにアプリケーションポリシーを設定します。

事前に以下の公式ドキュメントを参考にAAP用のアプリケーションを作成しておきます。

Cloudflare Zero TrustダッシュボードよりAccess > Applications > <AAP用のアプリケーション> > Policiesにアクセスして新規ポリシーを作成します。

設定項目は以下内容のとおりです。

  • ActionService Authにする
  • Create additional rulesに先程作成したService Tokenを指定する

image.png

これで、Service Tokenを使った通信は許可されWebhookを送信することが出来ます。

実際に手元のPCから以下curlを送ることでWebhookを実行できました。

curlコマンド
curl <Webhook URL> -X POST \
 -v \
 -H "Content-Type: application/json" \
 -H "X-Gitlab-Token: <Webhookキー>" \
 -H "CF-Access-Client-Id: <CFトークンID>" \
 -H "CF-Access-Client-Secret: <CFトークンシークレット>" \
 -d "{\"test\": \"test_cf\"}"

通信内容を見てみると以下の通りでサービストークンの通信をユーザ認証せずにそのまま許可してAAPのコンテンツを返しています。

また、レスポンスの中でCookieにCF_Authorizationが追加されJWTが入っています。
これで以降Cookieの有効期限まではサービストークンを使わなくてもCookieを使えば通信が許可されます。

curlコマンド結果
*   Trying 172.67.194.15:443...
* Connected to <AAP FQDN> (172.67.194.15) port 443 (#0)
# 省略
> POST <Webhook URLパス> HTTP/2
> Host: <AAP FQDN>
> user-agent: curl/7.76.1
> accept: */*
> content-type: application/json
> x-gitlab-token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> cf-access-client-id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access
> cf-access-client-secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> content-length: 21
>
# 省略
< set-cookie: CF_Authorization=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; Expires=Fri, 22 Sep 2023 23:23:36 GMT; Path=/; Secure; HttpOnly; SameSite=none
< access-control-expose-headers: X-API-Request-Id
< allow: POST, OPTIONS
< content-language: en
< vary: Accept, Accept-Language, Origin, Cookie
< x-api-node: xxxxxxxx
< x-api-product-name: Red Hat Ansible Automation Platform
< x-api-product-version: 4.2.0
< x-api-request-id: xxxxxxxxxxxxxxxxxxxxx
< x-api-time: 0.082s
< x-api-total-time: 0.193s
< cf-cache-status: DYNAMIC
< report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=xxxxxxxx"}],"group":"cf-nel","max_age":604800}
< nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< server: cloudflare
< cf-ray: xxxxx-NRT
< alt-svc: h3=":443"; ma=86400
<
# 省略

③GitLabからmain pushでWebhookをAAPに送信

最後に、GitLabからのWebhookを送信できるように設定します。

GitLabの変数定義

GitLabから今まで作成したWebhook URLやトークン情報をCI/CDで使えるように変数定義します。

全記事の①で作成したAAP構築プロジェクトページより、設定 > CI/CDの設定 > 変数にアクセスして以下のような変数を作成します。
トークン情報は、マスク属性をつけることで誤ってログなどに表示することを防ぐようにしておきます。

キー 属性
AAP_WEBHOOK_URL AAPのWebhook URL 保護 展開
GITLAB_TOKEN AAPのWebhookトークン 保護 マスク 展開
CF_ACCESS_CLIENT_ID CloudflareのトークンID 保護 マスク 展開
CF_ACCESS_CLIENT_SECRET Cloudflareのトークンシークレット 保護 マスク 展開

これで、GitLabから変数が使えるようになりました。

GitLab Runner設定

AAPのGitLab Webhookサービスは、もともとはGitLabのWebhook機能を使うことを想定しています。

しかし、②で定義したCloudflareトークンはヘッダー形式で設定する必要があり、GitLabではそれを設定することが出来ません。
(一応、以前から議論はされているようですが全く実装されていないようです。)

そのため、今回は.gitlab-ci.ymlを作成して、パイプラインからcurlコマンドで実行するようにしました。

先程作成した環境変数を使って以下のような.gitlab-ci.ymlを作成します。

.gitlab-ci.yml
workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

stages:
  - deploy

deploy-aap:
  stage: deploy
  script:
    - >-
      curl ${AAP_WEBHOOK_URL}
      -X POST
      -L
      -v
      -H "Content-Type: application/json"
      -H "CF-Access-Client-Id: ${CF_ACCESS_CLIENT_ID}"
      -H "CF-Access-Client-Secret: ${CF_ACCESS_CLIENT_SECRET}"
      -H "X-Gitlab-Token: ${GITLAB_TOKEN}"
      -d "{\"before\": \"${CI_COMMIT_BEFORE_SHA}\", \"after\": \"${CI_COMMIT_SHA}\"}"

これにより、mainにコミットプッシュをトリガーとしてパイプラインが起動してAAP側にジョブが実行されます。

AAP側にどんなheaderが来ているか見たかったので以下のとおり、Nginxのログ出力を変えてヘッダー内容を確認しました。

nginx.conf
    log_format main '"$request" $status $bytes_sent '
                'content-type: "$http_content_type" \n'
                'cookie: "$http_cookie" \n'
                'x-gitlab-token: "$http_x_gitlab_token" \n'
                'cf-access-client-id: "$http_cf_access_client_id" \n'
                'cf-access-client-secret: "$http_cf_access_client_secret"';
ログ出力
"POST /api/v2/job_templates/69/gitlab/ HTTP/1.1" 202 541 content-type: "application/json"
cookie: "CF_Authorization=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;"
x-gitlab-token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
cf-access-client-id: "-"
cf-access-client-secret: "-"

Cloudflareのトークン情報はAAP側まで届いておらず、Cloudflare側で取り除かれているようです。
一方、JWT情報(CF_Authorization)はサーバ側がCloudflare Zero Trustからの通信であることを証明するためそのまま残っています。

ちなみに、このCF_Authorizationを使って同じ組織の別アプリケーションにもアクセスしてMITM攻撃出来るか試してみましたが駄目でした。
どうやらアプリケーション or セッションごとにJWT発行しているようです

さいごに

本記事では、Cloudflare Zero Trust環境下のサーバにGitLabから外部アプリからアクセスする方法を紹介しました。

Cloudflare Zero Trustは機能が多すぎてなかなか検証しづらいですがいざ実際に使ってみるとドキュメントも揃っていて、すんなりと使いこなすことが出来ました。

また、細かいところでもセキュリティを担保するための技術が使われておりとても勉強になりました。

今回はGitLabからの利用でしたが同じようなクラウドとオンプレの通信をゼロトラスト技術で制御することが増えてくると思います。

製品によってこのあたりは思想が違ってくる部分でもあると思うので今後ゼロトラストを導入する上で検証が必要な観点だと感じました。

参考リンク

0
0
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
0
0