DEV Community

Cover image for [Post-Mortem] Deploying Athenz with Okta Sign-In: A Partial Success
Jeongwoo Kim
Jeongwoo Kim

Posted on • Edited on

[Post-Mortem] Deploying Athenz with Okta Sign-In: A Partial Success

Goal

[!TIP]
In hurry? Jump directly to Result section to see the outcome of this dive.

[!NOTE]
Although I am organizing and writing this on 2/21 after my LF AI & Data Japan RUG presentation has successfully concluded, I believe it is crucial to leave a record of failures and roadblocks. Therefore, I am documenting this past dive retrospectively.

The goal of this dive is to integrate Okta Sign-In with the Athenz ecosystem, by achieving the following:

  • Login into Athenz UI with Okta SSO
  • Successfully run zms-cli with Okta SSO

ToC

Result

I was able to login into Athenz UI successfully using Okta SSO.

login_as_ajkim_ajktown

However, due to the complexity of Identity mapping, I couldn't achieve the following goals:

  • Acting normally as the mapped user user.ajkim post-login. (The system authenticates me as the full email ajkim@ajktown.com, failing authorization checks).
  • Logging into zms-cli directly using the Okta integration.

Setup

Setup: Sign up Okta

sign_up_okta

https://developer.okta.com/signup/

Setup: Okta with Work Email

okta_verify

Setup: Okta Verify for Mac OS locally

Install Okta Verify from App Store.

okta_verify_for_mac_install

Test: Login Okta

Login completed!

okta_login_complete

Setup: Okta App Integration

[!TIP]
Official Athenz Doc: https://github.com/AthenZ/athenz/blob/master/docker/docs/IdP/Auth0.md

create_app_integration
https://integrator-8302118-admin.okta.com/admin/apps/active

Click next with OIDC & Web Application:

odic_n_web_app

  • Proof of possession: Makes required signed token, for now we skip

Setup: Okta Authorization Server API

authorization_server_api

https://integrator-8302118-admin.okta.com/admin/oauth2/as

Setup: Okta Policy & Rules

Create a scope athenz:

create_scope

Test: Token Preview

get_token_preview

Setup: sub as athenz user service name

[!NOTE]

Athenz only sees the sub field to define who you are. You can set up conversion field too but for now we can simply do this:

sub_as_user_sevice_name

Test: sub from Token Preview

test_sub_is_correct

Setup: Access Token

id_and_secret

CLIENT_ID="0oaz36xyehsYf8Cwz697"
CLIENT_SECRET="PUT_YOUR_SECRET_HERE"

curl -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "${CLIENT_ID}:${CLIENT_SECRET}" \
  "https://integrator-8302118.okta.com/oauth2/default/v1/token" \
  -d "grant_type=client_credentials" \
  -d "scope=athenz" | jq

# {
#   "token_type": "Bearer",
#   "expires_in": 3600,
#   "access_token": "CENSORED",
#   "scope": "athenz"
# }
Enter fullscreen mode Exit fullscreen mode

Test: Access Token

TOKEN="PUT_YOUR_ACCESS_TOKEN"
curl -k -H "Authorization: Bearer $TOKEN" \
  "https://localhost:4443/zms/v1/domain"
Enter fullscreen mode Exit fullscreen mode

Setup: Adding ZMS properties so that ZMS can trust the okta verify

zms_properties_setting

We can omit athenz.auth.oauth.jwt.authorized_client_ids_path because we setup the email address as the SSOT.

### Okta Configuration for ZMS ###

athenz.zms.authority_classes=com.yahoo.athenz.auth.impl.CertificateAuthority,com.yahoo.athenz.auth.impl.AuthorizedServiceAuthHeaderAuthority,com.yahoo.athenz.auth.oauth.OAuthCertBoundJwtAccessTokenAuthority

# Issuer:
athenz.auth.oauth.jwt.claim.aud=api://default
athenz.auth.oauth.jwt.claim.iss=https://integrator-8302118.okta.com/oauth2/default
athenz.auth.oauth.jwt.claim.scope=athenz

athenz.auth.oauth.jwt.parser.jwks_url=https://integrator-8302118.okta.com/oauth2/default/v1/keys
athenz.auth.oauth.jwt.auth0.claim_client_id=cid

athenz.auth.oauth.jwt.verify_cert_thumbprint=false
athenz.auth.oauth.jwt.cert.exclude_role_certificates=false

Enter fullscreen mode Exit fullscreen mode

zms_setting

Setup: Make sure to restart the ZMS server to get the changes!

kubectl rollout restart deployment/athenz-zms-server -n athenz
Enter fullscreen mode Exit fullscreen mode

Setup: Set k8s secret for proxy credentials

Athenz UI does not have any mechanism to handle the Oauth (completely separated) so we want to build our own proxy so that all Athenz cares is about the token stored as Cookie,

But before we do anything, we need the id and secret to represent the proxy so that proxy is trusted by Okta server. To do this correctly, we want to create a k8s secret:

printf "Enter Okta Client ID: "
read _CLIENT_ID
printf "Enter Okta Client Secret: "
read _CLIENT_SECRET
echo ""

_COOKIE_SECRET=$(openssl rand -base64 32 | tr -- '+/' '-_')
_ns="athenz"

echo "🔐 Creating Kubernetes Secret [oauth2-proxy-creds] in ns [$_ns]..."
kubectl delete secret oauth2-proxy-creds -n $_ns --ignore-not-found > /dev/null
kubectl create secret generic oauth2-proxy-creds \
  -n $_ns \
  --from-literal=client-id=${_CLIENT_ID} \
  --from-literal=client-secret=${_CLIENT_SECRET} \
  --from-literal=cookie-secret=${_COOKIE_SECRET}
Enter fullscreen mode Exit fullscreen mode

Setup: Create proxy container

Copy the following container spec right under the spec.template.spec.containers section:


      - name: oauth2-proxy
        image: quay.io/oauth2-proxy/oauth2-proxy:latest
        ports:
        - containerPort: 3100
          name: auth-proxy
        env:
        - name: OAUTH2_PROXY_CLIENT_ID
          valueFrom:
            secretKeyRef:
              name: oauth2-proxy-creds
              key: client-id
        - name: OAUTH2_PROXY_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              name: oauth2-proxy-creds
              key: client-secret
        - name: OAUTH2_PROXY_COOKIE_SECRET
          valueFrom:
            secretKeyRef:
              name: oauth2-proxy-creds
              key: cookie-secret
        args:
        # destination of this container:
        - --upstream=http://127.0.0.1:3000/
        # this container's port, the same as the .ports[0].containerPort:
        - --http-address=0.0.0.0:3100
        # Okta setting:
        - --provider=oidc
        - --oidc-issuer-url=https://integrator-8302118.okta.com/oauth2/default
        - --email-domain=*
        # "Athenz-Principal-Auth" is the default (modifiable) cookie name
        - --cookie-name=Athenz-Principal-Auth
        - --cookie-secure=false
        - --pass-access-token=true
        # Let the UI read?
        - --set-xauthrequest=true
        - --pass-user-headers=true
Enter fullscreen mode Exit fullscreen mode

Setup: Remove STATIC_USER_NAME

Remove the following line from the spec.template.spec.containers section, this is only for test and if you want to use the admin back, please do add them later once again:


        - name: STATIC_USER_NAME
          value: athenz_admin
Enter fullscreen mode Exit fullscreen mode

Setup: Modify the UI config

[!NOTE]
docker/ui/conf/extended-config.js

Modify

  • authUserEmailHeader to X-Forwarded-Email
  • authUserNameHeader to X-Forwarded-Preferred-Username:

fixed_wrongful_not_standard_prefix_name

Verify: Does it work?

Please refer to the Result section above to see the verification steps and outcome.

What I learned

Not every tech dive ends with a perfectly working architecture, and that is completely fine.

One of my core principles for maintaining a Weekly Dive habit is knowing how to manage failure gracefully. If I stubbornly pushed to resolve this Okta identity mapping issue, I would have compromised the preparation time for my upcoming LF AI & Data Japan RUG presentation.

By defining this as a [Post-Mortem], I accomplished two things:

  • I left a clear, reproducible architecture footprint (oauth2-proxy + Okta OIDC) that I can easily pick back up later.
  • I maintained my documentation consistency without feeling guilty about an "incomplete" project.

What's next?

For the next 4 weeks, my Weekly Dives will be entirely dedicated to an Epic: AI Data Japan RUG Prep. Sometimes the best engineering decision you can make is knowing when to pause a task, log the exact error state, and pivot to the higher-priority deadline.

Closing

If you enjoyed this deep dive, please leave a like & subscribe for more!

cats_thumbs_up

Top comments (0)