Cloud Platform as a Service

Cloud Platform as a Service

Join us to learn more from a community of collaborative experts and IBM Cloud product users to share advice and best practices with peers and stay up to date regarding product enhancements, regional user group meetings, webinars, how-to blogs, and other helpful materials.

 View Only

Part2: Utilize An OIDC Proxy to protect your Code Engine Apps

By Enrico Regge posted 17 days ago

  

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:

  1. 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.

  2. 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.

  3. 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.

  4. Token Verification
    The proxy validates the authorization code or token and retrieves the user information from the OIDC provider.

  5. 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.

Setup and Configuration

In this section, we will prepare the environment and required resources for running the sample application with IBM Cloud Code Engine:

  1. Install and configure the IBM Cloud CLI
    • Perform all necessary login steps to IBM Cloud 

  1. Create or select a Code Engine project

    • Create or select the Code Engine project of your choice; e.g.
      ibmcloud ce project create --name oidc-sample or
      ibmcloud ce project select --name <yourProjectName> 

  2. Deploy a sample application; e.g. a simple "Hello World" application provided in the Code Engine samples under https://github.com/IBM/CodeEngine/tree/main/hello

    • ibmcloud ce app create \
        --name origin-app \
        --image icr.io/codeengine/hello \
        --visibility project

    • Please note: This app is configured with the visibility "project". Hence, it does not expose a public endpoint to the internet and is only reachable from other components deployed in the same Code Engine project. To make this internal URL known to the oauth2-proxy app, we’ll store its value in an environment variable in your terminal session.

    • ORIGIN_APP_URL=$(ibmcloud ce app get -n origin-app --output project-url)

  3. Prepare configuration for oauth2-proxy

    • 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

  1. On github.com, navigate to Settings > Developer Settings https://github.com/settings/applications/new

  2. Provide an application name; e.g. "my-oauth2-proxy-sample"

  3. Put in the application URL as Homepage URL; e.g. "https://<app-name>.<proj-namespace>.<code-engine-region>.codeengine.appdomain.cloud/"

  4. 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"

  5. Complete this step by clicking "Register application"

  6. 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".

Once, that is done, you’ll see a rendered page within the content rendered by the origin application.

Precisely, the OAuth2 Proxy does not only take care of authentication and authorization, but also forwards useful information to the origin app, such as the username of the authenticated user. To explore the available headers, we’ll make use of the debug endpoint provided by Code Engine hello app. As you can see the X-Forwarded-Email, X-Forwarded-User corresponds to the GitHub user that had been authenticated.

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.

0 comments
8 views

Permalink