Authentication

K10 offers a variety of different ways to secure access to its dashboard and APIs:

Direct Access

When exposing the K10 dashboard externally, it is required that an authentication method is properly configured to secure access.

If accessing the K10 API directly or using kubectl, any authentication method configured for the cluster is acceptable. For more information, see Kubernetes authentication.

Basic Authentication

Basic Authentication allows you to protect access to the K10 dashboard with a user name and password. To enable Basic Authentication, you will first need to generate htpasswd credentials by either using an online tool or via the htpasswd binary found on most systems. Once generated, you need to supply the resulting string with the helm install or upgrade command using the following flags.

--set auth.basicAuth.enabled=true \
--set auth.basicAuth.htpasswd='example:$apr1$qrAVXu.v$Q8YVc50vtiS8KPmiyrkld0'

Alternatively, you can use an existing secret that contains a file created with htpasswd. The secret must be in the K10 namespace.

--set auth.basicAuth.enabled=true \
--set auth.basicAuth.secretName=my-basic-auth-secret

Token Authentication

To enable token authentication use the following flag as part of the initial Helm install or subsequent Helm upgrade command.

--set auth.tokenAuth.enabled=true

Once the dashboard is configured, you will be prompted to provide a bearer token that will be used when accessing the dashboard.

Obtaining Tokens

Token authentication allows using any token that can be verified by the Kubernetes server. For details on the supported token types see Authentication Strategies.

The most common token type that you can use is a service account bearer token.

You can use kubectl to extract such a token from a service account that you know has the proper permissions.

# Assume K10 is installed in the 'kasten-io' namespace
# Extracting token from SA 'my-kasten-sa'

# get the SA secret
$ sa_secret=$(kubectl get serviceaccount my-kasten-sa -o jsonpath="{.secrets[0].name}" --namespace kasten-io)

# extract token
$ kubectl get secret $sa_secret --namespace kasten-io -ojsonpath="{.data.token}{'\n'}" | base64 --decode

Alternatively, you can create a new service account from which to extract the token.

$ kubectl create serviceaccount my-kasten-sa --namespace kasten-io

In this case, you will need to create a role binding or cluster role binding for the account to ensure that it has the appropriate permissions for K10.

To learn more about the necessary K10 permissions, see Authorization.

Obtaining Tokens with Red Hat OpenShift

An authentication token can be obtained from Red Hat OpenShift via the OpenShift Console by clicking on your user name in the top right corner of the console and selecting Copy Login Command. Alternatively, the token can also be obtained by using the following command:

$ oc whoami --show-token

OAuth Proxy with Red Hat OpenShift (Preview)

The OpenShift OAuth proxy can be used for authenticating access to K10. The following resources have to be deployed in order to setup OAuth proxy in the same namespace as K10.

Configuration

ServiceAccount

Create a ServiceAccount that is to be used by the OAuth proxy deployment

apiVersion: v1
kind: ServiceAccount
metadata:
  name: k10-oauth-proxy
  namespace: kasten-io

Cookie Secret

Create a Secret that is used for encrypting the cookie created by the proxy. The name of the Secret will be used in the configuration of the OAuth proxy.

$ oc --namespace kasten-io create secret generic oauth-proxy-secret \
    --from-literal=session-secret=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c43)

ConfigMap for OpenShift Root CA

Create a ConfigMap annotated with the inject-cabundle OpenShift annotation. The annotation results in the injection of OpenShift's root CA into the ConfigMap. The name of this ConfigMap is used in the configuration of the OAuth proxy.

apiVersion: v1
kind: ConfigMap
metadata:
  annotations:
    service.beta.openshift.io/inject-cabundle: "true"
  name: service-ca
  namespace: kasten-io

NetworkPolicy

Create a NetworkPolicy to allow ingress traffic on port 8080 and port 8083 to to be forwarded to the OAuth proxy service.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-oauth-proxy
  namespace: kasten-io
spec:
  ingress:
  - ports:
    - port: 8083
      protocol: TCP
    - port: 8080
      protocol: TCP
  podSelector:
    matchLabels:
      service: oauth-proxy-svc
  policyTypes:
  - Ingress

Service

Deploy a Service for OAuth proxy. This needs to be annotated with the serving-cert-secret-name annotation. This will result in OpenShift generating a TLS private key and certificate that will be used by the OAuth proxy for secure connections to it. The name of the Secret used with the annotation must match with the name used in the OAuth proxy deployment.

apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.openshift.io/serving-cert-secret-name: oauth-proxy-tls-secret
  labels:
    service: oauth-proxy-svc
  name: oauth-proxy-svc
  namespace: kasten-io
spec:
  ports:
  - name: https
    port: 8083
    protocol: TCP
    targetPort: https
  - name: http
    port: 8080
    protocol: TCP
    targetPort: http
  selector:
    service: oauth-proxy-svc
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  type: ClusterIP
status:
  loadBalancer: {}

Deployment

Next, a Deployment for OAuth proxy needs to be created. It is recommended that a separate OpenShift OAuth client be registered for this purpose. The name of the client and its Secret will be used with the --client-id and --client-secret configuration options respectively.

When an OpenShift ServiceAccount was used as the OAuth client, it was observed that the token generated by the proxy did not have sufficient scopes to operate K10. It is therefore not recommended to deploy the proxy using an OpenShift ServiceAccount as the OAuth client.

It is also important to configure the --pass-access-token with the proxy so that it includes the OpenShift token in the X-Forwarded-Access-Token header when forwarding a request to K10.

The --scope configuration must have the user:full scope to ensure that the token generated by the proxy has sufficient scopes for operating K10.

The --upstream configuration must point to the K10 gateway Service.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: oauth-proxy-svc
  namespace: kasten-io
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      service: oauth-proxy-svc
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        service: oauth-proxy-svc
    spec:
      containers:
      - args:
        - --https-address=:8083
        - --http-address=:8080
        - --tls-cert=/tls/tls.crt
        - --tls-key=/tls/tls.key
        - --provider=openshift
        - --client-id=oauth-proxy-client
        - --client-secret=oauthproxysecret
        - --openshift-ca=/etc/pki/tls/cert.pem
        - --openshift-ca=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        - --openshift-ca=/service-ca/service-ca.crt
        - --scope=user:full user:info user:check-access user:list-projects
        - --cookie-secret-file=/secret/session-secret
        - --cookie-secure=true
        - --upstream=http://gateway:8000
        - --pass-access-token
        - --redirect-url=http://openshift.example.com/oauth2/callback
        - --email-domain=*
        image: openshift/oauth-proxy:latest
        imagePullPolicy: Always
        name: oauth-proxy
        ports:
        - containerPort: 8083
          name: https
          protocol: TCP
        - containerPort: 8080
          name: http
          protocol: TCP
        resources:
          requests:
            cpu: 10m
            memory: 20Mi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /service-ca
          name: service-ca
          readOnly: true
        - mountPath: /secret
          name: oauth-proxy-secret
          readOnly: true
        - mountPath: /tls
          name: oauth-proxy-tls-secret
          readOnly: true
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: k10-oauth-proxy
      serviceAccountName: k10-oauth-proxy
      terminationGracePeriodSeconds: 30
      volumes:
      - configMap:
          defaultMode: 420
          name: service-ca
        name: service-ca
      - name: oauth-proxy-tls-secret
        secret:
          defaultMode: 420
          secretName: oauth-proxy-tls-secret
      - name: oauth-proxy-secret
        secret:
          defaultMode: 420
          secretName: oauth-proxy-secret

OAuth Client

As mentioned earlier, it is recommended that a new OpenShift OAuth client be. registered.

The redirectURIs has to point to the domain name where K10 is accessible. For example if K10 is available at https://example.com/k10, the redirect URI should be set to https://example.com.

The name of this client must match with the --client-id configuration in the OAuth proxy deployment.

The Secret in this client must match with the --client-secret configuration in the OAuth proxy deployment.

The grantMethod can be either prompt or auto.

kind: OAuthClient
apiVersion: oauth.openshift.io/v1
metadata:
 name: oauth-proxy-client
secret: "oauthproxysecret"
redirectURIs:
 - "http://openshift4-4.aws.kasten.io"
grantMethod: prompt

Forwarding Traffic to the Proxy

Traffic meant for K10 must be forwarded to the OAuth proxy for authentication before it reaches K10. Ensure that ingress traffic on port 80 is forwarded to port 8080 and traffic on port 443 is forwarded to port 8083 of the oauth-proxy-svc Service respectively.

Here is one example of how to forward traffic to the proxy. In this example K10 was deployed with an external gateway Service. The gateway Service's ports were modified to forward traffic like so:

ports:
- name: https
  nodePort: 30229
  port: 443
  protocol: TCP
  targetPort: 8083
- name: http
  nodePort: 31658
  port: 80
  protocol: TCP
  targetPort: 8080
selector:
  service: oauth-proxy-svc

Sample Auth Flow with Screenshots

This section is meant to provide an example of configuring authentication and authorization for operating K10 in an OpenShift cluster to help provide an end to end picture of the Auth flow when working with the OAuth proxy.

  • Okta was configured as the OIDC provider in the OpenShift cluster.

  • An OpenShift group called k10-admins was created and users were added to this group.

  • A cluster role binding was created to bind the k10-admins group to the k10-admin cluster role.

  • A role binding was created to map the k10-admins group to the k10-ns-admin role in the K10 namespace.

  • When the user navigates to the K10 dashboard, the request reaches the proxy. The proxy presents a login screen to the user.

  • After clicking the login button, the user is forwarded to the OpenShift login screen. The OpenShift screen will provide the option of selecting kube:admin or the OIDC option if it has been configured in the cluster.

  • After clicking on the OIDC option okta in this example, the OIDC provider's login screen is shown.

  • When authentication with the OIDC provider succeeds, the user is redirected to the K10 dashboard.

Additional Documentation

For more information about the OpenShift OAuth proxy, refer to the documentation here.

OpenID Connect Authentication

For clusters that have been properly configured to use OpenID Connect (OIDC) Tokens, K10 supports the ability to obtain a token from an OIDC provider and then use that token for authentication. K10 extracts the user's ID from the token and uses Kubernetes User Impersonation with that ID to ensure that user-initiated actions (via the API, CLI or dashboard) are attributed to the authenticated user.

Cluster Setup

K10 works with your OIDC provider irrespective of whether the Kubernetes cluster is configured with the same OIDC provider, a different OIDC provider, or without any identity providers.

For more information on the Kubernetes API configuration options, see Configuring the API Server.

When working with a hosted Kubernetes offering (e.g. GKE, AKS, IKS) there will usually be specific instruction on how to enable this since you may not be able to explicitly configure the Kubernetes API server.

Overall, this portion of the configuration is beyond the scope of the K10 product and is part of the base setup of your Kubernetes cluster.

K10 Setup

Provider Redirect URI Authorizations

As part of the exchange with the OIDC provider, K10 will include a redirect URL in its request to the provider. The provider will return the user to that endpoint after the user has been authenticated. If the OIDC provider that you are using requires that redirects are specifically authorized, you will need to add the redirect URL to the provider's allow-list:

  • For a K10 instance exposed externally use https://<URL to k10 gateway service>/<k10 release name>/auth-svc/v0/oidc/redirect

  • For a K10 instance exposed through kubectl port-forward use http://127.0.0.1:<forwarding port>/<k10 release name>/auth-svc/v0/oidc/redirect

K10 Configuration

The final step is providing K10 with the settings needed to initiate the OIDC workflow and obtain a token.

  • Enable OIDC

    To enable OIDC based authentication use the following flag as part of the initial Helm install or subsequent Helm upgrade command.

    --set auth.oidcAuth.enabled=true
    
  • OIDC Provider

    This is a URL for OIDC provider. If the Kubernetes API server and K10 share the same OIDC provider, use the same URL that was used when configuring the --oidc-issuer-url option of the API server.

    Use the following Helm option:

    --set auth.oidcAuth.providerURL=<provider URL>
    
  • Redirect URL

    This is the URL to the K10 gateway service.

    Use https://<URL to k10 gateway service> for K10 exposed externally or http://127.0.0.1:<forwarding port> for K10 exposed through kubectl port-forward.

    Use the following Helm option:

    --set auth.oidcAuth.redirectURL=<gateway URL>
    
  • OIDC Scopes

    This option defines the scopes that should be requested from the OIDC provider. If the Kubernetes API server and K10 share the same OIDC provider, use the same claims that were requested when configuring the --oidc-username-claim option of the API server.

    Use the following Helm option:

    --set auth.oidcAuth.scopes=<space separated scopes. Quoted if multiple>
    
  • OIDC Prompt

    If provided, this option specifies whether the OIDC provider must prompt the user for consent or re-authentication. The well known values for this field are select_account, login, consent, and none. Check the OIDC provider's documentation to determine what value is supported. The default value is select_account.

    Use the following Helm option:

    --set auth.oidcAuth.prompt=<prompt>
    
  • OIDC Client ID

    This option defines the Client ID that is registered with the OIDC Provider. If the Kubernetes API server and K10 share the same OIDC provider, use the same client ID specified when configuring the --oidc-client-id option of the API server.

    Use the following Helm option:

    --set auth.oidcAuth.clientID=<client id string>
    
  • OIDC Client Secret

    This option defines the Client Secret that corresponds to the Client ID registered. You should have received this value from the OIDC provider when registering the Client ID.

    Use the following Helm option:

    --set auth.oidcAuth.clientSecret=<secret string>
    
  • OIDC User Name Claim

    This option defines the OpenID claim that has to be used by K10 as the user name. It will be used by K10 for impersonating the user while interacting with the Kubernetes API server for authorization. If not provided, the default claim is sub. This user name must match the User defined in the role bindings described here: K10 RBAC.

    Use the following Helm option:

    --set auth.oidcAuth.usernameClaim=<username claim>
    
  • OIDC User Name Prefix

    If provided, all usernames will be prefixed with this value. If not provided, username claims other than email are prefixed by the provider URL to avoid clashes. To skip any prefixing, provide the value -.

    Use the following Helm option:

    --set auth.oidcAuth.usernamePrefix=<username prefix>
    
  • OIDC Group Name Claim

    If provided, this specifies the name of a custom OpenID Connect claim to be used by K10 to identify the groups that a user belongs to. The groups and the username will be used by K10 for impersonating the user while interacting with the Kubernetes API server for authorization.

    To ensure that authorization for the user is successful, one of the groups should match with a Kubernetes group that has the necessary role bindings to allow the user to access K10.

    If the user is an admin user, then the user is most likely set up with all the required permissions for accessing K10 and no new role bindings are necessary.

    To avoid creating new role bindings for non-admin users every time a new user needs to be added to the list of users who will operate K10, consider adding the user to a group such as my-K10-admins in the OIDC provider and add that user to the same group in the Kubernetes cluster. Create role bindings to associate the my-K10-admins group with a cluster role - k10-admin and namespace scoped role - k10-ns-admin (see K10 RBAC for more information about these roles that are created by K10 as part of the installation process). This ensures that once a user is authenticated successfully with the OIDC provider, if the groups information from the provider matches the groups information in Kubernetes, it will authorize the user for accessing K10.

    Note that instead of my-k10-admins, if the user is added to k10:admins in the OIDC provider and to the same group in the Kubernetes cluster, no additional role bindings need to be created since K10 creates them as a part of the installation process.

    For more information about role bindings - K10 RBAC.

    Use the following Helm option:

    --set auth.oidcAuth.groupClaim=<group claim>
    
  • OIDC Group Prefix

    If provided, all groups will be prefixed with this value to prevent conflicts. To disable the group prefix, either remove this setting or set it to "".

    Use the following Helm option:

    --set auth.oidcAuth.groupPrefix=<group prefix>
    

Below is a summary of all the options together. These options can be included as part of the initial install command or can be used with a helm upgrade (see more about upgrade at Upgrading K10) command to modify an existing installation.

--set auth.oidcAuth.enabled=true \
--set auth.oidcAuth.providerURL="https://okta.example.com" \
--set auth.oidcAuth.redirectURL="https://k10.example.com/" \
--set auth.oidcAuth.scopes="groups profile email" \
--set auth.oidcAuth.prompt="select_account" \
--set auth.oidcAuth.clientID="client ID" \
--set auth.oidcAuth.clientSecret="client secret" \
--set auth.oidcAuth.usernameClaim="email" \
--set auth.oidcAuth.usernamePrefix="-" \
--set auth.oidcAuth.groupClaim="groups" \
--set auth.oidcAuth.groupPrefix=""

OpenShift Authentication

This mode can be used to authenticate access to K10 using OpenShift's OAuth server.

Prerequisite

Before installing/upgrading K10, a Service Account has to be created in a namespace where K10 is going to be installed. This Service Account represents an OAuth client that will interact with OpenShift's OAuth server.

If the K10 namespace currently does not exist, it must be created before creating the service account in it. Assuming that K10 will be installed in a namespace called kasten-io.

$ kubectl create namespace kasten-io

Assuming K10 is deployed with the release name k10 and the URL for accessing K10 is https://example.com/k10, use the following command to create a Service Account annotated with the serviceaccounts.openshift.io/oauth-redirecturi.dex annotation. This annotation registers the Service Account as an OAuth client with the OpenShift OAuth server.

$ cat > oauth-sa.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: k10-dex-sa
  namespace: kasten-io
  annotations:
    serviceaccounts.openshift.io/oauth-redirecturi.dex: https://example.com/k10/dex/callback
EOF

$ kubectl create -f oauth-sa.yaml

This will create a service account in the kasten-io namespace, it is necessary to retrieve the service account token to be used as a Helm option. To retrieve this token run the following command

$ kubectl -n kasten-io get secret $(kubectl -n kasten-io get sa k10-dex-sa -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 -d

To enable this mode of authentication, enable the following Helm options while installing/upgrading K10. Each Helm value is described in more detail in the next section.

$ helm upgrade k10 kasten/k10 --namespace kasten-io --reuse-values \
  --set auth.openshift.enabled=true \
  --set auth.openshift.serviceAccount="service account" \
  --set auth.openshift.clientSecret="token from the service account" \
  --set auth.openshift.dashboardURL="K10's dashboard URL" \
  --set auth.openshift.openshiftURL="OpenShift API server's URL" \
  --set auth.openshift.insecureCA=false
$ helm upgrade k10 kasten/k10 --reuse-values \
  --set auth.openshift.enabled=true \
  --set auth.openshift.serviceAccount="service account" \
  --set auth.openshift.clientSecret="token from the service account" \
  --set auth.openshift.dashboardURL="K10's dashboard URL" \
  --set auth.openshift.openshiftURL="OpenShift API server's URL" \
  --set auth.openshift.insecureCA=false

K10 Setup

  • Enable OpenShift Authentication

    To enable OpenShift based authentication use the following flag as part of the initial Helm install or subsequent Helm upgrade command.

    --set auth.openshift.enabled=true
    
  • OpenShift Service Account

    Provide the name of the Service Account created in the Prerequisite section using the following Helm option.

    --set auth.openshift.serviceAccount="k10-dex-sa"
    
  • OpenShift Service Account Token

    Provide the token corresponding to the Service Account used with the auth.openshift.serviceAccount Helm option. Use the following helm option.

    --set auth.openshift.clientSecret="Token from the service account k10-dex-sa"
    
  • K10's Dashboard URL

    Provide the URL used for accessing K10's dashboard using the following Helm option.

    --set auth.openshift.dashboardURL="https://<URL to k10 gateway service>/<k10 release name>"
    
  • OpenShift API Server URL

    Provide the URL for accessing OpenShift's API server using the following Helm option.

    --set auth.openshift.openshiftURL="OpenShift API server's URL"
    
  • Disabling TLS verification to OpenShift API server

    The default value for this setting is false. This means that connections to the API server are secure by default. The TLS connections to the API server are verified.

    To disable TLS verification, set this value to true.

    Use the following Helm option to enable or disable TLS verification of connections to OpenShift's API server.

    --set auth.openshift.insecureCA=false
    

Sample Auth Flow with Screenshots

This section shows screenshots depicting the Auth flow when K10 is installed with OpenShift authentication.

  • Okta was configured as the OIDC provider in the OpenShift cluster.

  • An OpenShift group called k10-admins was created and users were added to this group.

  • A cluster role binding was created to bind the k10-admins group to the k10-admin cluster role.

  • A role binding was created to map the k10-admins group to the k10-ns-admin role in the K10 namespace.

  • When the user navigates to the K10 dashboard, the user is redirected to OpenShift's login screen.

  • After clicking on the OIDC option okta in this example, the OIDC provider's login screen is shown.

  • When authentication with the OIDC provider succeeds, the user is redirected to the K10 dashboard.