OAuth2 ProxyをCloud FoundryのSidecarとしてデプロイする

前記事、"Cloud Foundryの複数Portに対するRouting"で、

また、Sidecarを使う場合も同じようにRouteをmapできます。

と書いていたので、その例としてOAuth2 Proxyをsidecarとして使う例を紹介します。

次の図のような構成を実装します。

image

次のバージョンで確認しました。

$ cf -v
cf version 6.50.0+4f0c3a2ce.2020-03-03

$ cf curl /v2/info | jq -r .build
2.8.6-build.15

Main Appの作成

ここではphp buildpackで作ったアプリをUpstreamのMain Appとして扱います。

Main Appは次のように作成します。

mkdir -p /tmp/demo-oauth2-proxy/htdocs
cd /tmp/demo-oauth2-proxy
echo 'Hello World!' > htdocs/index.html

このMain Appへアクセスする前にGithubで認証させるためにOAuth2 ProxyをReverse Proxとして使うことを今回の題材とします。

Main Appへ直接アクセスされることを防ぐため、デフォルトの設定である、Main App(8080ポート)へのRoutingは行いません。 代わりに同一コンテナ内にSidecarとして起動するOAuth2 Proxy(4180ポート)に対してのみRoutingします。

OAuth2 Proxyのダウンロード

次のコマンドでOAuth2 Proxyの実行可能バイナリをダウンロードしてください。

cd /tmp/demo-oauth2-proxy
curl -Ls https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v5.1.0/oauth2_proxy-v5.1.0.linux-amd64.go1.14.tar.gz | tar xzv && \
  mv oauth2_proxy-*/oauth2_proxy ./ && \
  rm -rf oauth2_proxy-*

Github OAuth2 Appの作成

https://github.com/settings/developersからGithub OAuth2 Appを登録します。

"New OAuth App"ボタンをクリックして、Authorization callback URLhttps://<TARGET_SUBDOMAIN>.<APPS_DOMAIN>/oauth2/callbackを入力してください。

下図の例ではTARGET_SUBDOMAIN=demo-oauth2-proxyAPPS_DOMAIN=apps.pcfone.ioです。 image

Client IDとClient Secretをメモしてください。 image

この値をUser Provider ServiceまたはCredHub Service Brokerに登録します。

User Provided Serviceの場合

cf create-user-provided-service github-oauth2-app -p '{"client_id": "3210067a78235e54fa17", "client_secret":"24c06ed8c2d6d7146c28e4cd72c4d18b63ef5bef"}'

CredHub Service Brokerの場合

cf create-service credhub default github-oauth2-app -c '{"client_id": "3210067a78235e54fa17", "client_secret":"24c06ed8c2d6d7146c28e4cd72c4d18b63ef5bef"}'

Main App及びSidecarのデプロイ

次のmanifest.ymlを作成してください。OAUTH2_PROXY_EMAIL_DOMAINSOAUTH2_PROXY_COOKIE_SECRETOAUTH2_PROXY_GITHUB_ORGは自分の環境に合わせて変更してください。

applications:
- name: demo-oauth2-proxy
  buildpacks:
  - php_buildpack
  memory: 64M
  services:
  - github-oauth2-app
  env:
    # Configurationの詳細は https://oauth2-proxy.github.io/oauth2-proxy/configuration
    OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
    OAUTH2_PROXY_EMAIL_DOMAINS: .pivotal.io,.vmware.com
    OAUTH2_PROXY_COOKIE_SECURE: true
    # 次のコマンドで生成。 python -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(16)).decode())'
    OAUTH2_PROXY_COOKIE_SECRET: 1pNTxc6qvV1rZBYobr0FUQ==
    OAUTH2_PROXY_UPSTREAMS: http://localhost:8080   
    OAUTH2_PROXY_PROVIDER: github
    OAUTH2_PROXY_GITHUB_ORG: pivotal
  sidecars:
  - name: oauth2-proxy
    process_types:
    - web
    command: |
      echo ${VCAP_SERVICES} | grep credhub
      if [ "$?" = "0" ];then
        CREDS=$(echo ${VCAP_SERVICES} | jq '.["credhub"][0].credentials')
      else
        CREDS=$(echo ${VCAP_SERVICES} | jq '.["user-provided"][0].credentials')
      fi
      export OAUTH2_PROXY_CLIENT_ID=$(echo ${CREDS} | jq -r .client_id)
      export OAUTH2_PROXY_CLIENT_SECRET=$(echo ${CREDS} | jq -r .client_secret)
      /home/vcap/app/oauth2_proxy

次のコマンドでデプロイしてください。

APP_NAME=demo-oauth2-proxy
TARGET_SUBDOMAIN=${APP_NAME}
APPS_DOMAIN=$(cf curl "/v2/shared_domains" | jq -r ".resources[0].entity.name")
CURRENT_SPACE=$(cat ~/.cf/config.json | jq -r ".SpaceFields.Name")

# 1. 
cf v3-create-app ${APP_NAME}
APP_GUID=$(cf app ${APP_NAME} --guid)

# 2.
cf curl "/v2/apps/${APP_GUID}" -X PUT -d "{\"ports\": [8080, 4180]}"

cf create-route ${CURRENT_SPACE} ${APPS_DOMAIN} --hostname ${TARGET_SUBDOMAIN}
ROUTE_GUID=$(cf curl "/v2/routes?q=host:${TARGET_SUBDOMAIN}" | jq -r ".resources[0].metadata.guid")

# 3.
cf curl "/v2/route_mappings" -X POST -d "{\"app_guid\": \"${APP_GUID}\", \"route_guid\": \"${ROUTE_GUID}\", \"app_port\": 4180}"

# 4. 
cf v3-apply-manifest -f manifest.yml 
cf v3-push ${APP_NAME}
  1. Sidecarを含むmanifestを使ってデプロイする場合は、先にappを作成する必要があります。[Doc]
  2. このコンテナが80804180をListenしていることを設定します。ここで設定したポートでヘルスチェックが行われます。通常Main Appはここで指定した一つ目のポートを使用するので、先頭を8080にするのが無難です。
  3. 作成したRouteにアクセスした場合に、このコンテナ内の4180ポートにマッピングされるように設定します。
  4. Sidecarを含むmanifestを適用します。

cf logs ${APP_NAME}を確認すると、次のようなログが出力されます。

   2020-04-11T23:51:16.84+0900 [API/1] OUT Starting app with guid 5a8769b7-4891-4f57-b6aa-0157f3e945dc
   2020-04-11T23:51:17.06+0900 [CELL/0] OUT Cell eda33d0c-120e-4025-991c-fd5f1c7d1e68 creating container for instance 291d8c06-72f4-4fbc-68ce-59be
   2020-04-11T23:51:17.79+0900 [CELL/0] OUT Cell eda33d0c-120e-4025-991c-fd5f1c7d1e68 successfully created container for instance 291d8c06-72f4-4fbc-68ce-59be
   2020-04-11T23:51:18.06+0900 [CELL/0] OUT Downloading droplet...
   2020-04-11T23:51:22.75+0900 [CELL/0] OUT Downloaded droplet (90.7M)
   2020-04-11T23:51:23.08+0900 [CELL/0] OUT Starting health monitoring of container
   2020-04-11T23:51:24.60+0900 [APP/PROC/WEB/SIDECAR/OAUTH2-PROXY/0] ERR [2020/04/11 14:51:24] [oauthproxy.go:215] mapping path "/" => upstream "http://localhost:8080/"
   2020-04-11T23:51:24.60+0900 [APP/PROC/WEB/SIDECAR/OAUTH2-PROXY/0] ERR [2020/04/11 14:51:24] [http.go:92] HTTP: listening on 0.0.0.0:4180
   2020-04-11T23:51:24.69+0900 [APP/PROC/WEB/0] OUT 14:51:24 httpd   | [Sat Apr 11 14:51:24.685558 2020] [mpm_event:notice] [pid 168:tid 140340045219712] AH00489: Apache/2.4.41 (Unix) configured -- resuming normal operations
   2020-04-11T23:51:24.69+0900 [APP/PROC/WEB/0] OUT 14:51:24 httpd   | [Sat Apr 11 14:51:24.685696 2020] [mpm_event:info] [pid 168:tid 140340045219712] AH00490: Server built: Jan  7 2020 15:08:24
   2020-04-11T23:51:24.69+0900 [APP/PROC/WEB/0] OUT 14:51:24 httpd   | [Sat Apr 11 14:51:24.685704 2020] [core:notice] [pid 168:tid 140340045219712] AH00094: Command line: '/app/httpd/bin/httpd -f /home/vcap/app/httpd/conf/httpd.conf -D FOREGROUND'
   2020-04-11T23:51:24.75+0900 [APP/PROC/WEB/0] OUT 14:51:24 php-fpm | [11-Apr-2020 14:51:24] NOTICE: fpm is running, pid 170
   2020-04-11T23:51:24.75+0900 [APP/PROC/WEB/0] OUT 14:51:24 php-fpm | [11-Apr-2020 14:51:24] NOTICE: ready to handle connections
   2020-04-11T23:51:26.69+0900 [CELL/0] OUT Container became healthy

デプロイが成功したらhttps://${TARGET_SUBDOMAIN}.${APPS_DOMAIN}にアクセスしてください。 未ログイン状態では次のようにOAuth2 Proxyの画面が表示されます。

image

"Sign in with GitHub"をクリックして、GitHubにログインしてください。

image

"Authorize"をクリック。

image

これでMain AppのHello World!が出力されます。

image


SidecarとRoute Mappingの応用を使ってReverse Proxyを同一コンテナ内に立てる方法を紹介しました。色々応用が効くと思います。