Coder Social home page Coder Social logo

authorino-validating-webhook's Introduction

Demo: Using Authorino as ValidatingWebhook service to validate other AuthConfigs applied to the cluster

Authorino provides an interface for raw HTTP external authorization requests. This interface can be used for integrations other than the typical Envoy gRPC protocol, such as using Authorino as a generic Kubernetes ValidatingWebhook service.

The rules to validate a request to the Kubernetes API – typically a POST, PUT or DELETE request targeting a particular Kubernetes resource or collection –, according to which either the change will be deemed accepted or not, are written in an Authorino AuthConfig custom resource. Authentication and authorization are performed by the Kubernetes API server as usual, with auth features of Authorino implementing the aditional validation within the scope of an AdmissionReview request.

This user guide provides an example of using Authorino as a Kubernetes ValidatingWebhook service that validates requests to CREATE and UPDATE Authorino AuthConfig resources. In other words, we will use Authorino as a validator inside the cluster that decides what is a valid AuthConfig for any application which wants to rely on Authorino to protect itself.

The AuthConfig to validate other AuthConfigs will enforce the following rules:

  • Only 'oidc' identity method can be used
  • Using Dex SSO server requires additional permission for the user defined in the Kubernetes RBAC

For convinience, the same instance of Authorino used to enforce the AuthConfig associated with the validating webhook will also be targeted for the sample AuthConfigs created to test the validation. For using different instances of Authorino for the validating webhook and for protecting applications behind a proxy, check out the section about sharding in the docs. There is also a user guide on the topic, with concrete examples.

Here's how the architecture and data plane (dotted lines) of using Authorino as a Validating Webhook service will look like:

Architecture


Requirements

1. Create the cluster: (▶︎)

kind create cluster --name authorino-demo

(Optional) Start watching the workloads in a separate terminal: (▶︎)

watch -n 3 "kubectl get pods --all-namespaces --user=kind-authorino-demo | grep -viE 'Completed|OOMKilled'"

2. Deploy the SSO servers

Deploy Keycloak: (▶︎)

kubectl create namespace keycloak
kubectl -n keycloak apply -f https://raw.githubusercontent.com/kuadrant/authorino-examples/main/keycloak/keycloak-deploy.yaml

Deploy Dex: (▶︎)

kubectl create namespace dex
kubectl -n dex apply -f https://raw.githubusercontent.com/kuadrant/authorino-examples/main/dex/dex-deploy.yaml

3. Install cert-manager (▶︎)

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.4.0/cert-manager.yaml

4. Install the Authorino Operator (▶︎)

kubectl apply -f https://raw.githubusercontent.com/Kuadrant/authorino-operator/main/config/deploy/manifests.yaml

5. Deploy Authorino

Create the namespace: (▶︎)

kubectl create namespace authorino

Create the TLS certificates: (▶︎)

curl -sSL https://raw.githubusercontent.com/Kuadrant/authorino/main/deploy/certs.yaml | sed "s/\$(AUTHORINO_INSTANCE)/authorino/g;s/\$(NAMESPACE)/authorino/g" | kubectl -n authorino apply -f -

Create the Authorino instance: (▶︎)

kubectl -n authorino apply -f -<<EOF
apiVersion: operator.authorino.kuadrant.io/v1beta1
kind: Authorino
metadata:
  name: authorino
spec:
  clusterWide: true
  listener:
    ports:
      http: 5001 # for admissionreview requests sent by the kube-api-server
    tls:
      certSecretRef:
        name: authorino-server-cert
  oidcServer:
    tls:
      certSecretRef:
        name: authorino-oidc-server-cert
EOF

6. Define the rules to validate the AuthConfig CRs

Create the AuthConfig: (▶︎)

kubectl -n authorino apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: authconfig-validator
spec:
  # admissionreview requests will be sent to this host name
  hosts:
  - authorino-authorino-authorization.authorino.svc

  # because we're using a single authorino instance for the validating webhook and to protect the user applications,
  # skip operations related to this one authconfig in the 'authorino' namespace
  when:
  - selector: context.request.http.body.@fromstr|request.object.metadata.namespace
    operator: neq
    value: authorino

  # kubernetes admissionreviews carry info about the authenticated user
  identity:
  - name: k8s-userinfo
    plain:
      authJSON: context.request.http.body.@fromstr|request.userInfo

  authorization:
  - name: check-identity
    opa:
      allValues: true
      inlineRego: |
        authconfig = json.unmarshal(input.context.request.http.body).request.object
        forbidden { authconfig.spec.identity[_].apiKey }
        forbidden { authconfig.spec.identity[_].oauth2 }
        forbidden { authconfig.spec.identity[_].kubernetes }
        forbidden { authconfig.spec.identity[_].plain }
        forbidden { authconfig.spec.identity[_].anonymous }
        using_dex { startswith(authconfig.spec.identity[_].oidc.endpoint, "http://dex") }
        allow { count(authconfig.spec.identity) > 0; not forbidden }

  - name: k8s-rbac
    priority: 1 # so it waits for the opa policy first
    when:
    - selector: auth.authorization.check-identity.using_dex
      operator: eq
      value: "true"
    kubernetes:
      user:
        valueFrom: { authJSON: auth.identity.username }
      resourceAttributes:
        namespace: { value: authorino }
        group: { value: sso.company.com }
        resource: { value: dex }
        verb: { value: use }
EOF

Define a Role to control the usage of Dex: (▶︎)

kubectl -n authorino apply -f -<<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dex-user
rules:
- apiGroups: ["sso.company.com"]
  resources: ["dex"] # not a real k8s resource
  verbs: ["use"] # not a real k8s verb
EOF

7. Create the ValidatingWebhookConfiguration (▶︎)

kubectl apply -f -<<EOF
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: authconfig-authz
  annotations:
    cert-manager.io/inject-ca-from: authorino/authorino-ca-cert
webhooks:
- name: check-authconfig.authorino.kuadrant.io
  clientConfig:
    service:
      namespace: authorino
      name: authorino-authorino-authorization
      port: 5001
      path: /check
  rules:
  - apiGroups: ["authorino.kuadrant.io"]
    apiVersions: ["v1beta1"]
    resources: ["authconfigs"]
    operations: ["CREATE", "UPDATE"]
    scope: Namespaced
  sideEffects: None
  admissionReviewVersions: ["v1"]
EOF

8. Create a namespace and Kubernetes user for the next steps

Set the user credentials: (▶︎)

openssl genrsa -out /tmp/john.key
openssl req -new -key /tmp/john.key -out /tmp/john.csr -subj "/CN=john"

kubectl apply -f -<<EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: john
spec:
  request: $(cat /tmp/john.csr | base64 | tr -d '\n')
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth
  - digital signature
  - key encipherment
  groups:
  - system:authenticated
EOF

kubectl certificate approve john
kubectl get csr/john -o jsonpath='{.status.certificate}' | base64 -d > /tmp/john.crt
kubectl config set-credentials john --client-certificate=/tmp/john.crt --client-key=/tmp/john.key --embed-certs=true

Create a namespace and grant permissions for the user: (▶︎)

kubectl create namespace apps
kubectl create role namespace-owner --verb="*" --resource="*.*" -n apps
kubectl create rolebinding namespace-owners --role=namespace-owner --user=john -n apps

Set the Kubernetes context: (▶︎)

kubectl config set-context --current --user=john --namespace=apps

9. Try it out

AuthConfig with forbidden identity method (▶︎)

kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: myapp-protection
spec:
  hosts:
  - myapp.io
  identity:
  - name: api-key
    apiKey:
      labelSelectors: { app: myapp }
EOF

Output:

Error from server: error when creating "STDIN": admission webhook "check-authconfig.authorino.kuadrant.io" denied the request: Unauthorized

AuthConfig with Keycloak (▶︎)

kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: myapp-protection
spec:
  hosts:
  - myapp.io
  identity:
  - name: keycloak
    oidc:
      endpoint: http://keycloak.keycloak.svc.cluster.local:8080/auth/realms/kuadrant
EOF

Output:

authconfig.authorino.kuadrant.io/myapp-protection created

AuthConfig with Dex

Without permission: (▶︎)

kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: myapp-protection
spec:
  hosts:
  - myapp.io
  identity:
  - name: keycloak
    oidc:
      endpoint: http://keycloak.keycloak.svc.cluster.local:8080/auth/realms/kuadrant
  - name: dex
    oidc:
      endpoint: http://dex.dex.svc.cluster.local:5556
EOF

Output:

Error from server: error when applying patch:
{"metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"authorino.kuadrant.io/v1beta1\",\"kind\":\"AuthConfig\",\"metadata\":{\"annotations\":{},\"name\":\"myapp-protection\",\"namespace\":\"apps\"},\"spec\":{\"hosts\":[\"myapp.io\"],\"identity\":[{\"name\":\"keycloak\",\"oidc\":{\"endpoint\":\"http://keycloak.keycloak.svc.cluster.local:8080/auth/realms/kuadrant\"}},{\"name\":\"dex\",\"oidc\":{\"endpoint\":\"http://dex.dex.svc.cluster.local:5556\"}}]}}\n"}},"spec":{"identity":[{"name":"keycloak","oidc":{"endpoint":"http://keycloak.keycloak.svc.cluster.local:8080/auth/realms/kuadrant"}},{"name":"dex","oidc":{"endpoint":"http://dex.dex.svc.cluster.local:5556"}}]}}
to:
Resource: "authorino.kuadrant.io/v1beta1, Resource=authconfigs", GroupVersionKind: "authorino.kuadrant.io/v1beta1, Kind=AuthConfig"
Name: "myapp-protection", Namespace: "apps"
for: "STDIN": admission webhook "check-authconfig.authorino.kuadrant.io" denied the request: Not authorized: unknown reason

As admin, grant permission to the user: (▶︎)

kubectl --user=kind-authorino-demo -n authorino apply -f -<<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dex-users
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: dex-user
subjects:
- kind: User
  name: john
EOF

Try again with permission: (▶︎)

kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta1
kind: AuthConfig
metadata:
  name: myapp-protection
spec:
  hosts:
  - myapp.io
  identity:
  - name: keycloak
    oidc:
      endpoint: http://keycloak.keycloak.svc.cluster.local:8080/auth/realms/kuadrant
  - name: dex
    oidc:
      endpoint: http://dex.dex.svc.cluster.local:5556
EOF

Output:

authconfig.authorino.kuadrant.io/myapp-protection configured

Cleanup (▶︎)

kind delete cluster --name authorino-demo
kubectl config unset users.john

authorino-validating-webhook's People

Contributors

guicassolato avatar

Watchers

James Cloos avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.