Written by
Simon Daniel Moser (smoser@de.ibm.com) - Distinguished Engineer for Containers @ IBM Cloud
Enrico Regge (reggeenr@de.ibm.com) - Software Architect @ IBM Cloud
----------------------------------
In the first part of this article series, we demonstrated how to secure access to a Code Engine application using OIDC with an external identity provider. As you may recall, this approach required modifications to the application’s source code. However, in many scenarios you may not have that flexibility—updating the application code is not always feasible or even possible.
In such cases, OIDC supports another integration pattern: placing a reverse proxy in front of your application. The proxy handles authentication and ensures that only requests from legitimate callers reach your application. This architecture provides an additional security advantage as well: only the reverse proxy is exposed to the internet, while your application runs behind it on a private network.
As you might expect, the reverse OAuth proxy is the key component in this approach. Because implementing such a proxy from scratch is non-trivial, our example uses the battle-tested, open-source OAuth2 Proxy available at the project’s website https://oauth2-proxy.github.io/oauth2-proxy/. We recommend considering the same solution if you plan to secure your own application using this integration pattern.
Figure 1 below illustrates the component setup and authentication flow:
-
Initial Request
The flow begins when a user accesses your application’s URL without presenting any authentication token (for example, a header, cookie, or session identifier). The application’s public URL is served by the OAuth proxy that sits in front of it.
-
Redirect to OIDC Provider
Detecting the absence of valid authentication, the proxy immediately redirects the user to the configured OIDC provider to initiate the login process.
-
User Authentication
The user then authenticates with the OIDC provider. Once authentication succeeds, the provider redirects the user back to the proxy, this time including the required authorization code or token.
-
Token Verification
The proxy validates the authorization code or token and retrieves the user information from the OIDC provider.
-
Forwarding to the Application
If verification is successful, the proxy forwards the request to your application. This communication occurs over the private network, ensuring that only authenticated traffic reaches the application.
-
-
To provide necessary configuration information, we’ll eventually create a Code Engine secret that exposes relevant information to the application as environment variables. For now, create a temporary file located on your local workstation called "oauth2-proxy.properties" that contains the following content:
OAUTH2_PROXY_COOKIE_SECRET=<see-next-steps>
OAUTH2_PROXY_CLIENT_ID=<see-next-steps>
OAUTH2_PROXY_CLIENT_SECRET=<see-next-steps>
OAUTH2_PROXY_PROVIDER=github
OAUTH2_PROXY_EMAIL_DOMAINS=*
OAUTH2_PROXY_COOKIE_SECRET
As the value for the property OAUTH2_PROXY_COOKIE_SECRET, we’ll generate an base64 encoded sequence which is used as a seed string for secure cookies (see seed string for secure cookies for further details). The value must either comprise of 16, 24, or 32 bytes to create an AES cipher. The following command can be used to generate and encryption key from your terminal window:
dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-_' ; echo
OIDC_CLIENT_ID & OIDC_CLIENT_SECRET
Before registering a new GitHub OAuth app, we’ll need to determine the homepage and callback URLs of our application. In principal both URL pattern starts with: "https://<app-name>.<proj-namespace>.<code-engine-region>.codeengine.appdomain.cloud".
The <app-name> should correspond to the public facing name that you want to surface. Assuming, you’ll want to expose your app with the name "my-app", the run the following command in your local terminal to craft the base URL:
CE_PROJECT=$(ibmcloud ce project current --output json)
CE_PROJECT_DOMAIN=$(echo "$CE_PROJECT" | jq -r '.domain')
CE_PROJECT_NAMESPACE=$(echo "$CE_PROJECT" | jq -r '.kube_config_context')
echo "https://my-app.${CE_PROJECT_NAMESPACE}.${CE_PROJECT_DOMAIN}"
Register a new OAuth app in GitHub.com
-
On github.com, navigate to Settings > Developer Settings https://github.com/settings/applications/new
-
Provide an application name; e.g. "my-oauth2-proxy-sample"
-
Put in the application URL as Homepage URL; e.g. "https://<app-name>.<proj-namespace>.<code-engine-region>.codeengine.appdomain.cloud/"
-
As "Authorization callback URL", use the value of the Homepage URL and append the route "/oauth2/callback"; e.g. "https://<app-name>.<proj-namespace>.<code-engine-region>.codeengine.appdomain.cloud/oauth2/callback"
-
Complete this step by clicking "Register application"
-
On the next page, GitHub.com provides necessary meta information and credentials necessary to establish the trust relation with the application that initiates the OIDC flow
-
Copy the Client ID and paste into the "oauth2-proxy.properties" as value for the property OAUTH2_PROXY_CLIENT_ID
-
Click "Generate a new client secret", to obtain a new client secret. Use the value as property OAUTH2_PROXY_CLIENT_SECRET
Now that we have all configuration values at hand, let us create the Code Engine secret:
ibmcloud ce secret create \
--name oauth2-proxy-credentials \
--from-env-file oauth2-proxy.properties
Finally, we’ll create OAuth2 Proxy app and attach the secret that contains the GitHub OAuth credentials
ibmcloud ce app create --name my-app \
--image quay.io/oauth2-proxy/oauth2-proxy:latest-amd64 \
--port 4180 \
--memory 0.5G \
--cpu 0.25 \
--env-from-secret oauth2-proxy-credentials \
--env OAUTH2_PROXY_REVERSE_PROXY=true \
--env OAUTH2_PROXY_UPSTREAMS=$ORIGIN_APP_URL \
--env OAUTH2_PROXY_SKIP_PROVIDER_BUTTON=true \
--env OAUTH2_PROXY_SSL_UPSTREAM_INSECURE_SKIP_VERIFY=true \
--env OAUTH2_PROXY_PASS_HOST_HEADER=false \
--env OAUTH2_PROXY_PROXY_WEBSOCKETS=true \
--scale-down-delay 300
Once the application has been deployed, open the browser and enter the public URL of the app.
You’ll be redirected to GitHub.com, once you’ve passed the authentication you’ll be asked you to authorize the OAuth app "my-oauth2-proxy-sample".
Summary and Outlook
In this article, we demonstrated a second method for securing access to your Code Engine application: using an OAuth2 Proxy with GitHub as the external OIDC provider. There are, however, many ways to further strengthen and extend this setup. We recommend exploring the full range of configuration options available in OAuth2 Proxy, documented here: https://oauth2-proxy.github.io/oauth2-proxy/configuration/overview.
For example, you may prefer not to use GitHub as your OIDC/OAuth2 provider. OAuth2 Proxy supports a wide variety of alternative identity providers—including Google, Apple, and many others—which you can review here: https://oauth2-proxy.github.io/oauth2-proxy/configuration/providers/.
Finally, in Part 3 of this series, we’ll show even more advanced scenarios — we’ll be looking at a more real world application that e.g. utilises web sockets — something that the OAuth2 Proxy might be struggling with.