Modern Advanced Authentication for Kubernetes API Gateway
Tags: kubernetes, apigateway, api, authentication
Published: 2024-04-15 06:00:00

## What is Authentication?

Authentication is the process of verifying the identity of a user or system. It's a way to ensure that the entity requesting access is who they claim to be. Authentication is one of the core attributes of a Kubernetes API gateway. As the main access point from the outside world to your application and services, your gateway must be well protected from bad actors and unauthorized access.

The problem? Traditional authentication mechanisms aren’t up to the challenge of preventing unauthorized access and protecting against sophisticated attacks in modern, complex environments like Kubernetes. Simple username and password authentication or even basic token-based authentication may not provide sufficient security for your API gateway.

Advanced authentication mechanisms are essential to address these challenges. These mechanisms go beyond the basics and incorporate additional layers of security to ensure that only authorized users or systems can access your API gateway and the services it exposes.

## Traditional Authentication and Where it Fails

Traditional authentication methods, such as Basic Authentication and API keys, have been widely used to secure access to APIs and services. However, these methods have limitations and fail to provide adequate security in modern, complex environments like Kubernetes.

## Basic Authentication

Basic Authentication is a simple authentication scheme where a client sends a username and password in the HTTP headers to authenticate with a server. The credentials are encoded using Base64 and sent in the "Authorization" header with each request. This makes for apparent issues:

**Credentials are sent in plaintext:** Although Base64 encoding is used, it is easily decodable, making the credentials vulnerable to interception if the communication channel is not encrypted (e.g., using HTTPS).

**No protection against replay attacks:** If an attacker captures the Base64-encoded credentials, they can reuse them to gain unauthorized access to the API.
**Lack of granular access control:** Basic Authentication does not provide fine-grained access control. Once authenticated, a user can access all resources the API exposes.
**API Keys
**API keys are unique identifiers that are used to authenticate and authorize access to an API. Clients include the API key in the request headers or as a query parameter to authenticate with the API server. The limitations of API keys are:

**Lack of encryption:** API keys are often sent in plaintext over the network, making them susceptible to interception if the communication channel is insecure.
**Shared secrets**: API keys are shared secrets between the client and the server. If an API key is compromised, an attacker can use it to gain unauthorized access to the API.
Difficulty in managing revocation: Revoking or updating API keys can be challenging, especially in distributed systems like Kubernetes, where multiple services and instances may share the same API key.
These options shouldn’t be used in any scenarios, but in a Kubernetes environment, these traditional authentication methods have additional limitations:

**Lack of integration with Kubernetes native security features:** Kubernetes provides built-in security features like Role-Based Access Control (RBAC) and service accounts. Traditional authentication methods do not seamlessly integrate with these features, making enforcing consistent access control policies across the cluster harder.

**Scalability and complexity:** Kubernetes clusters can have many services, pods, and instances. Managing and distributing API keys or Basic Authentication credentials across all these components becomes complex and error-prone, especially in a dynamically scaling environment.

**Insufficient authentication granularity: **Kubernetes deployments often involve multiple services and APIs with different access requirements. Traditional authentication methods do not provide sufficient granularity to enforce fine-grained access control at the API level, leading to potential security risks.

**Lack of support for modern authentication protocols: **Modern authentication protocols like OAuth 2.0 and OpenID Connect (OIDC) provide additional security features, such as token-based authentication, authorization scopes, and identity management. Traditional authentication methods do not natively support these protocols, limiting the ability to leverage their benefits in a Kubernetes environment.

## What does this mean for authentication for Kubernetes API gateways?

Gateways with these authentication mechanisms are susceptible to unauthorized access, security breaches, and potential compromise of the entire Kubernetes cluster.

To mitigate these risks and ensure robust security, Kubernetes API gateways must adopt advanced authentication mechanisms that are purpose-built for the unique challenges of Kubernetes environments.

## Modern Advanced Authentication Mechanisms With Kubernetes API Gateways

Several advanced authentication mechanisms have emerged to address the limitations of traditional authentication methods and enhance the security of Kubernetes API gateways. These mechanisms provide more robust, flexible, and secure authentication and authorization capabilities.

**OAuth 2.0
**OAuth 2.0 is an industry-standard authorization protocol. It enables secure delegated access to resources on behalf of a user or client application. OAuth 2.0 introduces the concept of access tokens, which are issued by an authorization server to a client application after successful authentication and authorization.

## Critical concepts in OAuth 2.0:

**Resource Owner:** The user or entity that owns the protected resources and can grant access to them.
Client: The application or service that wants to access the protected resources on behalf of the resource owner.
Authorization Server: The server responsible for authenticating the resource owner and issuing access tokens to the client.
**Resource Server: **The server hosting the protected resources capable of accepting and responding to protected resource requests using access tokens.

**OAuth 2.0 defines several grant types: **Authorization Code Grant, Implicit Grant, Resource Owner Password Credentials Grant, and Client Credentials Grant. Each grant type has its flow and is suitable for different scenarios.

## Benefits of OAuth 2.0 in a Kubernetes environment:

**Delegated authorization:** OAuth 2.0 allows clients to access resources on behalf of users without the need to share credentials.
**Granular access control:** OAuth 2.0 supports scopes, which define the specific permissions and access levels granted to a client.
**Token-based authentication:** Access tokens provide a secure way to authenticate and authorize requests to the Kubernetes API gateway.
**Integration with external identity providers:** OAuth 2.0 enables integration with external identity providers, allowing users to authenticate using their existing credentials.

**OpenID Connect (OIDC)**
OpenID Connect (OIDC) is an authentication layer built on OAuth 2.0. While OAuth 2.0 focuses on authorization, OIDC extends it to provide authentication capabilities. OIDC introduces the concept of ID tokens, which contain claims about the authenticated user.

## Critical concepts in OIDC:

**ID Token: **A JSON Web Token (JWT) that contains claims about the authenticated user, such as the user's ID, email, and other profile information.
**UserInfo Endpoint: **An endpoint provided by the OIDC provider that returns additional claims about the authenticated user.
**Discovery Document:** A JSON document that describes the OIDC provider's configuration, including the endpoints, supported scopes, and cryptographic algorithms.

OIDC defines several flows, including the Authorization Code Flow, Implicit Flow, and Hybrid Flow, which determines how the ID token and access token are obtained.

## Benefits of OIDC in a Kubernetes environment:

**Authentication and user identity:** OIDC provides a standardized way to authenticate users and obtain their identity information.
**Single Sign-On (SSO):** OIDC enables SSO, allowing users to authenticate once and access multiple services without needing separate logins.
**Integration with external identity providers:** OIDC supports integration with popular identity providers, such as Google, Facebook, and Azure AD, simplifying user management and authentication.

**Mutual TLS (mTLS) Authentication
**
Mutual TLS (mTLS) authentication is a mechanism where the client and the server authenticate each other using X.509 certificates. In mTLS, the client presents its certificate to the server, and the server verifies the client's certificate. Similarly, the server presents its certificate to the client, and the client verifies the server's certificate.

## Critical concepts in mTLS:

**Client Certificate:** An X.509 certificate that identifies the client and is presented to the server during the TLS handshake.
**Server Certificate:** An X.509 certificate that identifies the server and is presented to the client during the TLS handshake.
**Certificate Authority (CA):** A trusted entity that issues and signs the certificates used in mTLS authentication.
Benefits of mTLS in a Kubernetes environment:

**Strong authentication:** mTLS provides strong authentication by verifying the identities of both the client and the server.
Encryption: mTLS ensures that the client and server communication is encrypted, protecting sensitive data from eavesdropping.
**Defense against man-in-the-middle attacks:** mTLS helps prevent man-in-the-middle attacks by ensuring both parties have the correct certificates issued by a trusted CA.
Integration with Kubernetes: Kubernetes supports mTLS authentication natively, allowing secure communication between services within the cluster.
**JSON Web Tokens (JWTs)**
JSON Web Tokens (JWTs) are compact, URL-safe tokens used for authentication and authorization. JWTs consist of three parts: a header, a payload, and a signature. The header contains metadata about the token, the payload contains claims (statements) about the user or additional information, and the signature ensures the token's integrity.

## Critical concepts in JWTs:

**Claim**: A piece of information asserted about the user or the token itself, such as the user's ID, expiration time, or issuer.
**Signature**: A cryptographic signature verifies the token's integrity and ensures it hasn't been tampered with.
Signing Algorithms: JWTs can be signed using various algorithms, such as HMAC (symmetric) or RSA (asymmetric), to ensure their integrity and authenticity.
Benefits of JWTs in a Kubernetes environment:

**Stateless authentication:** JWTs enable stateless authentication, eliminating the need for server-side session storage.
**Scalability**: JWTs can be verified independently by multiple services, making them suitable for scalable and distributed architectures like Kubernetes.
**Fine-grained access control:** JWTs can carry claims representing user roles, permissions, or other attributes, enabling fine-grained access control decisions.
Integration with external systems: JWTs can be easily integrated with external authentication providers or identity management systems.
These advanced authentication mechanisms provide a higher level of security and flexibility compared to traditional authentication methods.

**Integrating Advanced Authentication Mechanisms With Kubernetes API Gateways
**The next step is to integrate these into your Kubernetes API gateway. Integrating advanced authentication mechanisms with a Kubernetes API gateway involves configuring the gateway to support the desired authentication methods and implementing the necessary components and flows. Let's explore some implementation strategies, configuration tips, and best practices for each approach with a Kubernetes API gateway.

**OAuth 2.0 and OIDC Integration
**To integrate OAuth 2.0 and OIDC with a Kubernetes API gateway, you must configure the gateway to act as an OAuth 2.0 client and/or an OIDC relying party. First, select a suitable OAuth 2.0 and OIDC provider based on your requirements, such as Google, Facebook, Azure AD, or a custom provider. Register your API gateway as a client application with the chosen provider and obtain the necessary client credentials (client ID and client secret).

Then, configure the API gateway to support OAuth 2.0 and OIDC authentication. Specify the OAuth 2.0 and OIDC provider's endpoints, such as the authorization, token, and UserInfo endpoints. Configure the gateway to validate access tokens and ID tokens received from the provider. You must define the required scopes and claims for authentication and authorization.

Afterward, you must implement the appropriate OAuth 2.0 and OIDC flow based on your use case (e.g., Authorization Code Flow, Implicit Flow, or Hybrid Flow). Redirect the user to the provider's authorization endpoint for authentication and consent. Handle the provider's callback and exchange the authorization code for access tokens and ID tokens. Validate the tokens received from the provider and extract the relevant claims.

## OAuth 2.0 and OIDC integration best practices:

Use a well-established and trusted OAuth 2.0 and OIDC provider to leverage their security measures and reduce the implementation overhead.

Follow the principle of least privilege and request only the necessary scopes and claims for your application.
Securely store and handle client credentials, access tokens, and refresh tokens.

Implement proper token validation, including checking the token's signature, expiration, and audience.

Use secure communication channels (HTTPS) for all API gateway, provider, and client interactions.

**mTLS Authentication Integration
**To integrate mTLS authentication with a Kubernetes API gateway, you must configure the gateway to require client certificates and validate them against a trusted certificate authority (CA).

The first step is to generate and sign client certificates using a trusted CA. Then, the client certificates are distributed securely to the intended clients, and the API gateway is configured with the server certificate and the trusted CA certificate.

You can then enable mTLS authentication in the API gateway configuration. Specify the server certificate and the trusted CA certificate for client certificate validation and configure the gateway to require client certificates for authentication. To implement client authentication, configure the clients to present their client certificates during the TLS handshake. Ensure the clients trust the server certificate and the CA that signed it.

## mTLS authentication best practices:

Use a dedicated CA to issue and sign client certificates to maintain control over the certificate issuance process.
Securely store and distribute client certificates to prevent unauthorized access.
Regularly rotate and update certificates to reduce the impact of potential certificate compromises.
Implement certificate revocation mechanisms to invalidate compromised or expired certificates.
Monitor and audit the use of client certificates to detect and respond to any suspicious activities.
JWT Integration
To integrate JWTs with a Kubernetes API gateway, you need to configure the gateway to validate and extract claims from clients' JWTs.

Select a trusted JWT issuer, such as an OAuth 2.0 provider or a custom JWT issuer, to generate and sign the JWTs. Then, configure the API gateway with the JWT issuer's public key or the shared secret used for token validation.

Enable JWT authentication in the API gateway configuration. Specify the JWT validation parameters, such as the expected issuer, audience, and signature algorithm. Define the claims extraction rules to extract relevant information from the JWT. When a client requests a JWT, the API gateway should validate the token's signature, expiration, and other claims. Extract the relevant claims from the JWT and use them to make authentication and authorization decisions.

## JWT Best practices:

Use a secure and well-established JWT issuer to ensure the integrity and trustworthiness of the tokens.
Properly validate the JWT's signature using the issuer's public key or the shared secret.
Check the token's expiration time and implement token refresh mechanisms if needed.
Validate the token's audience claim to ensure the token is intended for your API gateway.
Avoid storing sensitive information in the JWT payload, as it can be easily decoded.
Implement secure token storage and handling mechanisms to prevent token leakage or unauthorized access.
When integrating advanced authentication mechanisms with a Kubernetes API gateway, consider the scalability and performance implications. Ensure the authentication processes are efficiently implemented and handle the expected load. Additionally, regularly monitor and audit the authentication mechanisms to detect and respond to any security incidents or anomalies.

## Implementing Advanced Authentication Mechanisms With Edge Stack

Let’s examine how to do each of these with [Edge Stack](https://www.getambassador.io/products/edge-stack/api-gateway), which is main Kubernetes-centric API Gateway. For more detailed information, see the Edge Stack documentation.

## OAuth 2.0 and OIDC Integration

**Choose an Identity Provider (IdP):** Select an OAuth/OIDC-compliant IdP like Keycloak, Auth0, Okta, etc. Each IdP will have its specific configuration steps.
**Configure the OAuth2 Filter:
**authorizationURL: The URL of your IdP's OAuth2/OIDC discovery endpoint.
**extraAuthorizationParameters:** Additional parameters for the authorization request, such as the audience (identifies your application).
**clientID**: The client ID provided by your IdP.
secret: The client secret provided by your IdP.
protectedOrigins: List the domains protected by this authentication rule.
**Create a FilterPolicy:** Link the OAuth2 Filter you created to the specific services or URLs you want to protect.
Apply the Configurations: Save your Filters and FilterPolicies in a YAML file and apply it to your Kubernetes cluster using kubectl apply -f <filename.yaml>.
Example Configuration (adjust for your IdP):


a

```
piVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
  name: oauth-filter
  namespace: default
spec:
  OAuth2:
    authorizationURL: https://<idp-domain>/oauth2/default 
    audience: my-app 
    clientID: <your-client-id>
    secret: <your-client-secret> 
    protectedOrigins:
      - origin: https://www.example.com 
```

```
`---
apiVersion: getambassador.io/v3alpha1
kind: FilterPolicy
metadata:
  name: oauth-policy 
  namespace: default 
spec:
  rules:
    - host: "www.example.com" 
      path: /protected-path/* 
      filters:
        - name: oauth-filter`
```
Review the [Edge Stack](https://www.getambassador.io/products/edge-stack/api-gateway) OAuth/OIDC documentation for more detail.

## mTLS Authentication Integration

1. Certificates and Keys:

Obtain Certificates: You'll need a Certificate Authority (CA) to issue certificates for both your upstream services and for Ambassador Edge Stack itself. You can use a public CA or set up your own.
Store in Kubernetes Secrets: Create Kubernetes Secrets to hold the certificates and keys for both Ambassador Edge Stack and your upstream services.
2. Create a TLSContext:

This Kubernetes object tells Edge Stack where to find the certificates for mTLS.

```
apiVersion: getambassador.io/v3alpha1
kind: TLSContext
metadata:
     name: upstream-context
spec:
     hosts: []
     secret: upstream-certs
```
3. Configure Your Mappings:

Modify existing Mappings to enable mTLS.

`apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: my-service-mapping
spec:
  hostname: "*"
  prefix: /myservice/
  service: https://my-service 
  tlsContext:
    name: upstream-context ` # Use the context you created
(Optional) Client Certificate Validation:
You can configure Edge Stack API Gateway to require and validate client certificates presented by upstream services. 

Check the official documentation for details.
Some key points:

hosts: [] This is important in the TLSContext because we're using it for upstream authentication, not TLS termination.
Secret Names: Ensure the secret names in your configuration match the actual Kubernetes Secrets you created.
Upstream Service Readiness: Your upstream services must be configured and ready to engage in the mTLS handshake.
Certificate Management: Have a strategy for certificate renewal and rotation to maintain security.
Error Handling: Test your setup and understand the error states that can occur with mTLS, as misconfigurations can halt communication.
Review the Edge Stack mTLS Documentation for more detail.

## JWT Integration

Obtain JWKS (JSON Web Key Set):
JWKS is a set of public keys used to validate the JWT's signature.
Your authentication provider will typically expose a JWKS endpoint.
Create a JWT Filter:
This filter defines how Ambassador will validate the JWT.

`
# Example results are for the JWT:
#
#    eyJhbGciOiJub25lIiwidHlwIjoiSldUIiwiZXh0cmEiOiJzbyBtdWNoIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
#
# To save you some time decoding that JWT:
#
#   header = {
#     "alg": "none",
#     "typ": "JWT",
#     "extra": "so much"
#   }
#   claims = {
#     "sub": "1234567890",
#     "name": "John Doe",
#     "iat": 1516239022
#   }`
---
`apiVersion: getambassador.io/v3alpha1
kind: Filter
metadata:
  name: example-jwt-filter
  namespace: example-namespace
spec:
  JWT:
    jwksURI: "https://getambassador-demo.auth0.com/.well-known/jwks.json"
    validAlgorithms:
      - "none"
    audience: "myapp"
    requireAudience: false
    injectRequestHeaders:
      - name: "X-Fixed-String"
        value: "Fixed String"
        # result will be "Fixed String"
      - name: "X-Token-String"
        value: "{{ .token.Raw }}"
        # result will be "eyJhbGciOiJub25lIiwidHlwIjoiSldUIiwiZXh0cmEiOiJzbyBtdWNoIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."
      - name: "X-Token-H-Alg"
        value: "{{ .token.Header.alg }}"
        # result will be "none"
      - name: "X-Token-H-Typ"
        value: "{{ .token.Header.typ }}"
        # result will be "JWT"
      - name: "X-Token-H-Extra"
        value: "{{ .token.Header.extra }}"
        # result will be "so much"
      - name: "X-Token-C-Sub"
        value: "{{ .token.Claims.sub }}"
        # result will be "1234567890"
      - name: "X-Token-C-Name"
        value: "{{ .token.Claims.name }}"
        # result will be "John Doe"
      - name: "X-Token-C-Optional-Empty"
        value: "{{ .token.Claims.optional }}"
        # result will be "<no value>"; the header field will be set
        # even if the "optional" claim is not set in the JWT.
      - name: "X-Token-C-Optional-Unset"
        value: "{{ if hasKey .token.Claims \"optional\" | not }}{{ doNotSet }}{{ end }}{{ .token.Claims.optional }}"
        # Similar to "X-Token-C-Optional-Empty" above, but if the
        # "optional" claim is not set in the JWT, then the header
        # field won't be set either.
        #
        # Note that this does NOT remove/overwrite a client-supplied
        # header of the same name.  In order to distrust
        # client-supplied headers, you MUST use a Lua script to
        # remove the field before the Filter runs (see below).
      - name: "X-Token-C-Iat"
        value: "{{ .token.Claims.iat }}"
        # result will be "1.516239022e+09" (don't expect JSON numbers
        # to always be formatted the same as input; if you care about
        # that, specify the formatting; see the next example)
      - name: "X-Token-C-Iat-Decimal"
        value: "{{ printf \"%.0f\" .token.Claims.iat }}"
        # result will be "1516239022"
      - name: "X-Token-S"
        value: "{{ .token.Signature }}"
        # result will be "" (since "alg: none" was used in this example JWT)
      - name: "X-Authorization"
        value: "Authenticated {{ .token.Header.typ }}; sub={{ .token.Claims.sub }}; name={{ printf \"%q\" .token.Claims.name }}"
        # result will be: "Authenticated JWT; sub=1234567890; name="John Doe""
      - name: "X-UA"
        value: "{{ .httpRequestHeader.Get \"User-Agent\" }}"
        # result will be: "curl/7.66.0" or
        # "Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0"
        # or whatever the requesting HTTP client is
    errorResponse:
      headers:
      - name: "Content-Type"
        value: "application/json"
      - name: "X-Correlation-ID"
        value: "{{ .httpRequestHeader.Get \"X-Correlation-ID\" }}"
      # Regarding the "altErrorMessage" below:
      #   ValidationErrorExpired = 1<<4 = 16
      # https://godoc.org/github.com/dgrijalva/jwt-go#StandardClaims
      bodyTemplate: |-
        {
            "errorMessage": {{ .message | json "    " }},
            {{- if .error.ValidationError }}
            "altErrorMessage": {{ if eq .error.ValidationError.Errors 16 }}"expired"{{ else }}"invalid"{{ end }},
            "errorCode": {{ .error.ValidationError.Errors | json "    "}},
            {{- end }}
            "httpStatus": "{{ .status_code }}",
            "requestId": {{ .request_id | json "    " }}
        }
---
apiVersion: getambassador.io/v3alpha1
kind: Module
metadata:
  name: ambassador
spec:
  config:
    lua_scripts: |
      function envoy_on_request(request_handle)
        request_handle:headers():remove("x-token-c-optional-unset")
      end

Create a FilterPolicy:
Link the JWT filter to specific URLs or services you want to protect.

Copy

---
apiVersion: getambassador.io/v3alpha1
kind: FilterPolicy
metadata:
  name: "example-filter-policy"
  namespace: "example-namespace"
spec:
  rules:
  - host: "*"
    path: "*"
    filters:
    - name: "example-jwt-filter"
      arguments:
        scope:                    # optional; default is []
        - "scope-value-1"
        - "scope-value-2"`
Some important considerations:

**jwksURI**: Point this to the JWKS endpoint provided by your authentication provider.
**claims**: Verify necessary claims within the JWT using requiredClaims to ensure only valid tokens are accepted (e.g., issuer, audience).
**Error Handling:** Define how requests with invalid or missing JWTs should be handled (e.g., return a 401 Unauthorized response).
Review the for more information.

## Embracing Advanced Authentication for Robust API Security

Advanced authentication mechanisms like OAuth 2.0, OIDC, mTLS, and JWTs provide robust security for Kubernetes API gateways, addressing the limitations of traditional authentication methods.

Integrating these mechanisms means you can secure access to your APIs, protect against unauthorized access, and scale your authentication processes effectively. Edge Stack simplifies the implementation of these advanced authentication mechanisms, offering a declarative configuration approach and seamless integration with Kubernetes.

By leveraging [Edge Stack's](https://www.getambassador.io/products/edge-stack/api-gateway) features and following best practices, you can establish a secure and reliable authentication framework for your API gateway, safeguarding your applications and services from potential security threats.