Skip to main content

IBM Application Gateway Sidecar Example

The IBM Application Gateway can be deployed in Kubernetes alongside an application using the sidecar pattern. This allows an application developer with limited or no understanding of the IBM Application Gateway configuration to add a predefined set of annotations to the application deployment YAML to create the required sidecar container.

Sidecar Deployment Model

The sidecar deployment of IBM Application Gateway is suitable when:

  • The application to protect is a Kubernetes application
  • IBM Application Gateway annotations can be added to the application deployment YAML
  • A one to one mapping of application to IBM Application Gateway is desirable

Example

The following steps will:

  • Setup the IBM Application Gateway admission controller and webhook server
  • Create an application that will be fronted by IBM Application Gateway
  • Access the application via the IBM Application Gateway
  • The page will show the identity and other headers that have been added to the request by the IBM Application Gateway

Steps 1 - 17 are required to setup the IBM Application Gateway admission controller. To deploy further applications other than the one listed in the subsequent steps, the admission controller setup does NOT need to be performed again.

Note: This example does not include authentication. This example illustrates the deployment process for using IBM Application Gateway as a proxy to a protected application. For details on adding authentication, refer to Configuring as an OIDC Relying Party for IBM Security Verify or Configuring as an OIDC Relying Party for IBM Security Verify Access.

Note: This example uses Minikube with a docker driver

  1. Start Minikube with the mutating webhook plugin enabled.
minikube start --extra-config=apiserver.enable-admission-plugins="MutatingAdmissionWebhook" --driver docker
  1. Set context.
kubectl config use-context minikube
eval $(minikube docker-env)
  1. Create self signed certificates for communication between Kubernetes and the webhook server.
openssl req -nodes -new -x509 -keyout ca.key -out ca.crt -subj "/CN=IBM Application Gateway Webhook CA"
openssl genrsa -out webhook-server-tls-key.pem 2048
openssl req -new -key webhook-server-tls-key.pem -subj "/CN=ibm-application-gateway-injector-webhook-svc.default.svc" | openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -out webhook-server-tls-crt.pem
kubectl create secret generic ibm-application-gateway-webhook-certs --from-file=key.pem=webhook-server-tls-key.pem --from-file=cert.pem=webhook-server-tls-crt.pem --dry-run -o yaml | kubectl apply -f -
  1. Paste the following into a file named service_account.yaml.
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ibm-application-gateway-operator
  1. Create the operator service account.
kubectl apply -f service_account.yaml
  1. Paste the following into a file named rbac.yaml.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: ibm-application-gateway-operator
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - services
  - services/finalizers
  - endpoints
  - persistentvolumeclaims
  - events
  - configmaps
  - secrets
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - apps
  resources:
  - deployments
  - deployments/status
  - daemonsets
  - replicasets
  - statefulsets
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - monitoring.coreos.com
  resources:
  - servicemonitors
  verbs:
  - get
  - create
- apiGroups:
  - apps
  resourceNames:
  - ibm-application-gateway-operator
  resources:
  - deployments/finalizers
  verbs:
  - update
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - apps
  resources:
  - replicasets
  - deployments
  verbs:
  - get
- apiGroups:
  - ibm.com
  resources:
  - '*'
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch

---  

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ibm-application-gateway-operator
subjects:
- kind: ServiceAccount
  name: ibm-application-gateway-operator
roleRef:
  kind: Role
  name: ibm-application-gateway-operator
  apiGroup: rbac.authorization.k8s.io
  1. Create the role binding.
kubectl apply -f rbac.yaml
  1. Paste the following into a file named crd.yaml.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ibmapplicationgateways.ibm.com
spec:
  group: ibm.com
  names:
    kind: IBMApplicationGateway
    listKind: IBMApplicationGatewayList
    plural: ibmapplicationgateways
    singular: ibmapplicationgateway
  scope: Namespaced
  subresources:
    status: {}
    scale:
      # specReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Spec.Replicas.
      specReplicasPath: .spec.replicas
      # statusReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Replicas.
      statusReplicasPath: .status.replicas
      # labelSelectorPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Selector.
      labelSelectorPath: .status.labelSelector
  validation:
    openAPIV3Schema:
      description: IAG is the Schema for the iags API
      properties:
        apiVersion:
          description: 'APIVersion defines the versioned schema of this representation
            of an object. Servers should convert recognized schemas to the latest
            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
          type: string
        kind:
          description: 'Kind is a string value representing the REST resource this
            object represents. Servers may infer this from the endpoint the client
            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
          type: string
        metadata:
          type: object
        spec:
          description: IAGSpec defines the desired state of IAG.
          type: object
          properties:
            replicas:
              type: integer
              description: The number of IBM Application Gateway replicas to create.
            deployment:
              type: object
              description: Defines the IBM Application Gateway deployment properties. 
              properties:
                image:
                  description: The name, tag and location of the IBM Application Gateway docker image.
                  type: string
                imagePullPolicy:
                  description: The policy used to decide when to pull the IBM Application Gateway docker image from a remote server. Default value is IfNotPresent.
                  type: string
                  enum:
                    - Never
                    - Always
                    - IfNotPresent
                imagePullSecrets:
                  type: array
                  description: A list of Kubernetes secrets that will be set on the IBM Application Gateway deployment.
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                        description: The name of the Kubernetes secret that defines the required remote server authentication credentials.
                    required:
                      - name
                serviceAccountName:
                  description: The Kubernetes service account that will run the IBM Application Gateway applications.
                  type: string
                lang:
                  description: The language for the IBM Application Gateway application. Default value is English (en).
                  type: string
                readinessProbe:
                  type: object
                  description: The settings for the readiness probe.
                  properties:
                    initialDelaySeconds:
                      description: The initial delay (in seconds) before starting the IBM Application Gateway application readiness poll. Default value is 0. Minimum value is 0.
                      type: integer
                      minimum: 0
                    periodSeconds:
                      description: The wait period (in seconds) between IBM Application Gateway application readiness polling. Default value is 10. Minimum value is 1.
                      type: integer
                      minimum: 1
                    failureThreshold:
                      description: The number of times the probe will be tried before failing. Failure will result in the Pod will be marked Unready. Default value is 3. Minimum value is 1. 
                      type: integer
                      minimum: 1
                    successThreshold:
                      description: The number of consecutive successes for the probe to be considered successful after having failed. Default value is 1. Minimum value is 1. 
                      type: integer
                      minimum: 1
                    timeoutSeconds: 
                      description: The number of seconds after which the probe times out. Default value is 1. Minimum value is 1.
                      type: integer
                      minimum: 1
                livenessProbe:
                  type: object
                  description: The settings for the liveness probe.
                  properties:
                    initialDelaySeconds:
                      description: The initial delay (in seconds) before starting the IBM Application Gateway application liveness poll. Default value is 0. Minimum value is 0.
                      type: integer
                      minimum: 0
                    periodSeconds:
                      description: The wait period (in seconds) between IBM Application Gateway application liveness polling. Default value is 10. Minimum value is 1.
                      type: integer
                      minimum: 1
                    failureThreshold:
                      description: The number of times the probe will be tried before failing. Failure will result in the container being restarted. Default value is 3. Minimum value is 1. 
                      type: integer
                      minimum: 1
                    timeoutSeconds: 
                      description: The number of seconds after which the probe times out. Default value is 1. Minimum value is 1.
                      type: integer
                      minimum: 1
              required:
                - image
            configuration:
              type: array
              description: Defines the IBM Application Gateway configuration properties.
              items:
                type: object
                properties:
                  type:
                    type: string
                    enum:
                      - configmap
                      - literal
                      - web
                      - oidc_registration
                  name:
                    type: string
                    description: The name of the config map that contains the IBM Application Gateway configuration. Required for configmap type.
                  dataKey:
                    type: string
                    description: The config map YAML entry that contains the IBM Application Gateway configuration. Required for configmap type.
                  value:
                    type: string
                    description: The IBM Application Gateway configuration YAML text. Required for literal type.
                  url:
                    type: string
                    description: The URL location of the remote IBM Application Gateway configuration. Required for web type.
                  discoveryEndpoint:
                    type: string
                    description: The discovery endpoint used to retrieve the OIDC OP registration endpoint to dynamically register a new client. Required for oidc_registration type.
                  postData: 
                    type: array
                    description: A list of keys and values that will be added to the registration request as POST data. This must include the mandatory redirect_uris value. Required for oidc_registration type.
                    items:
                      type: object
                      properties:
                        name: 
                          type: string
                          description: The key name of the data value to add to the request.
                        value: 
                          type: string
                          description: A single data value to add to the request. If this property is specified the values property will be ignored. Required if the values property has not been specified.
                        values:
                          type: array
                          description: A list of data values to add to the request as an array. If the value property has been specified this property will be ignored. Required if the value property has not been specified.
                          items:
                            type: string
                      required:
                        - name
                  secret:
                    type: string
                    description: The name of a Kubernetes secret that contains any authorization data required for the OIDC client registration. The resulting client_id and secret will also be added to this secret. Required for oidc_registration type.
                  headers:
                    type: array
                    description: A list of headers to add to the HTTP request to retrieve the configuration source.
                    items:
                      type: object
                      properties:
                        type:
                          type: string
                          description: The value type. A literal type will add the value directly to the new header. A secret type will lookup a Kubernetes secret to retrieve the value.
                          enum:
                            - literal
                            - secret
                        name:
                          type: string
                          description: The name of the header that will be added to the HTTP request.
                        value:
                          type: string
                          description: The value of the header that will be added to the HTTP request. If the type is set as secret this will be the name of the Kubernetes secret.
                        secretKey:
                          type: string
                          description: The key name to retrieve the header value from the specified Kubernetes secret. Required if the type is set as secret.
                      required:
                        - type
                        - name
                        - value
                required:
                  - type
        status:
          description: IAGStatus defines the observed state of IAG
          type: object
      type: object
  version: v1
  versions:
  - name: v1
    served: true
    storage: true
  1. Deploy the custom resource definition.
kubectl apply -f crd.yaml
  1. Paste the following into a file named operator.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ibm-application-gateway-operator
  labels:
    app: ibm-application-gateway-injector
spec:
  replicas: 1
  selector:
    matchLabels:
      name: ibm-application-gateway-operator
      app: ibm-application-gateway-injector
  template:
    metadata:
      labels:
        name: ibm-application-gateway-operator
        app: ibm-application-gateway-injector
    spec:
      serviceAccountName: ibm-application-gateway-operator
      containers:
        - name: ibm-application-gateway-operator
          image: ibmcom/ibm-application-gateway-operator:20.09.0
          command:
          - ibm-application-gateway-operator
          imagePullPolicy: IfNotPresent
          env:
            - name: WATCH_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: OPERATOR_NAME
              value: "ibm-application-gateway-operator"
          volumeMounts:
          - name: webhook-certs
            mountPath: /etc/webhook/certs
            readOnly: true
      volumes:
      - name: webhook-certs
        secret:
          secretName: ibm-application-gateway-webhook-certs
  1. Deploy the operator (webhook server).
kubectl apply -f operator.yaml
  1. Ensure the webhook server has started correctly.
kubectl get all

NAME                                                    READY   STATUS    RESTARTS   AGE
pod/ibm-application-gateway-operator-5b55989d98-w22n9   1/1     Running   0          61s

NAME                                               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
service/ibm-application-gateway-operator-metrics   ClusterIP   10.97.147.42   <none>        8383/TCP,8686/TCP   58s
service/kubernetes                                 ClusterIP   10.96.0.1      <none>        443/TCP             20m

NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ibm-application-gateway-operator   1/1     1            1           61s

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/ibm-application-gateway-operator-5b55989d98   1         1         1       61s
  1. Paste the following into a file named webhook_service.yaml.
apiVersion: v1
kind: Service
metadata:
  name: ibm-application-gateway-injector-webhook-svc
  namespace: default
  labels:
    app: ibm-application-gateway-injector
spec:
  ports:
  - port: 443
    targetPort: 8443
  selector:
    app: ibm-application-gateway-injector
  1. Create the service to expose the webhook server port 443.
kubectl apply -f webhook_service.yaml
  1. Paste the following into a file named webhook.yaml.
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: ibm-application-gateway-injector-webhook-cfg
  labels:
    app: ibm-application-gateway-injector
webhooks:
- name: ibm-application-gateway-injector.ibm.com
  admissionReviewVersions: ["v1", "v1beta1"]
  sideEffects: NoneOnDryRun
  clientConfig:
    service:
      name: ibm-application-gateway-injector-webhook-svc
      namespace: default
      path: "/mutate"
    caBundle: "<certificate>" 
  rules:
  - operations: ["CREATE", "UPDATE", "DELETE"]
    apiGroups: ["apps", ""]
    apiVersions: ["v1"]
    resources: ["deployments"]
  1. In the webhook.yaml file replace the <certificate> macro with the value of the certificate in the Kubernetes secret that was created in step 3.
kubectl get secrets/ibm-application-gateway-webhook-certs -o jsonpath="{.data.cert\.pem}"

Copy the result of the kubectl command into the caBundle value of the YAML.

For example:

caBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM3RENDQWRRQ0NRQzg2TytzNXR4d1NEQU5CZ2txaGtpRzl3MEJBUVVGQURBdE1Tc3dLUVlEVlFRRERDSkoKUWswZ1FYQndiR2xqWVhScGIyNGdSMkYwWlhkaGVTQlhaV0pvYjI5cklFTkJNQjRYRFRJd01EWXlNakF6TkRjegpObG9YRFRJd01EY3lNakF6TkRjek5sb3dRekZCTUQ4R0ExVUVBd3c0YVdKdExXRndjR3hwWTJGMGFXOXVMV2RoCmRHVjNZWGt0YVc1cVpXTjBiM0l0ZDJWaWFHOXZheTF6ZG1NdVpHVm1ZWFZzZEM1emRtTXdnZ0VpTUEwR0NTcUcKU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRREFlbTFKNkpNam9UVUVoOEtWRWpVN0gzc0hNeWRjZEk0SwpIT0dmeklWc2xPOFFPTFhuU1B2aVZhZXltRit1REMwa0ZLZEc2VXM0N1pEMmkxUmNEY0Z6U01xN3QwUEg1K0pNCllpOXI3U3BYeWlvbStYczNKTGZyQUxSclArSXp6Ky96ZUVmSzJ6VUZaTVdZclRBYXlwaGhGRGhIYVdySHVaNXIKV0NRYjZRSEhnZm0vTTZpM0ZqQWFSZkl6S3IzdkJPTzdlSlM4elVvTFdMVlFsejVmVEtFd05WMVI3Z21iL1VkMQpleGxSVzlNcWJLVmZCU1N6TjIvajkvMktOd09YYUF5cGVsK0hzMFRzNCtvK0NNTXFlS0ZwNmNPcGpIZy9KRDg2Cks4Y0RaWHRVbmhUQ3V1ZVo1RGFJVlllcWk2UHdtRDhQVjdCUVI4ZE81amFxVmVhRVNKMXZBZ01CQUFFd0RRWUoKS29aSWh2Y05BUUVGQlFBRGdnRUJBQnh2T0I1a2ZtYUorSFdVbTYrckZ5enZ3cFFTc2ZYTGNjb25GVHZrTEFQZApSZHJvc2JTZS8zM3oxd0JWaGhGdFo5Q2NEbEJ0bkhSTGdtbVE1T1pLNHZsNlUwYzVuZW83ZVdTcjkxd2VKcUxYClV2bG5kb2dMc25KUkQrYUxSS0tzQ2xoSWJUWW5XNk9qK3h4RUdiQzAyTFN1cjdFNU9UZnc1YlJIRjk2U0pwZjUKUjl0R0xuSEdtdHluQjhzSkQ2d0w2dWFXa0d4N2M4YWxRM3FJNm5lMlFGdEFMM0pBemx2OXRsQUNkTmdtUW55RQpxVzQ1MjRvZFFPU2l5OE51c2ovTFJ3ck5qNzIrZDJ4Q3RxeHNwNkpucU9mU1RKZVA0Tk5OVm1PZ0ZBMHJzWmR6CkVSeFZTRm1oRUtERm9wS2tIeSsvMFNWcDRnSzJRTStOWjlDbTRvcUxqaG89Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
  1. Deploy the configuration to register the IBM Application Gateway admission controller with Kubernetes.
kubectl apply -f webhook.yaml
  1. Note that at this point the setup of the IBM Application Gateway admission controller is complete. The following steps (apart from cleanup) can be run multiple times using the same admission controller setup.

  2. Paste the following into a file named test_config.yaml.

apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config
data:
  config: |
    version: 20.09
    resource_servers:
      - path: /demo-local
        connection_type: tcp
        servers:
        - host: localhost
          port: 8000
        identity_headers:
          attributes:
          - attribute: AZN_CRED_AUTHNMECH_INFO
            header: mech_info
          - attribute: AZN_CRED_REGISTRY_ID
          jwt:
            certificate: |
              -----BEGIN CERTIFICATE-----
              MIIDSzCCAjOgAwIBAgIUFeqbJIDD0ITJN12OXKLNR9FaLaYwDQYJKoZIhvcNAQEL
              BQAwNTELMAkGA1UEBhMCdXMxDDAKBgNVBAoMA2libTEYMBYGA1UEAwwPd3d3Lmlh
              Z2RlbW8uY29tMB4XDTIwMDUxNTAwMDQyOVoXDTIxMDUxNTAwMDQyOVowNTELMAkG
              A1UEBhMCdXMxDDAKBgNVBAoMA2libTEYMBYGA1UEAwwPd3d3LmlhZ2RlbW8uY29t
              MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAssbA0VB0WTikufBOVaUC
              tIDyVQ9tknM7yxVg+pJc7zA/nVWvNbZ+sV6lVi1E9wPcKDvH1dd9N9mAOK9E1/KK
              Nma8+o5Q10k1OSDaPR50aHY6iukFOJiGaM0L3FVsmJO6i0UXZ1ZztkPHM3xEE6rm
              BYvgBYCeHSmMNWrdh/U8Pnte2dKn5GImOLzyK/CeZJpiE/HXsDGY68BedAQSClZn
              TMQNpM6Rynmbn7tRrCf6aUDhFnmrcHea3WldI5dJzPe2UD0k3EBdO/S/yA6bEZ5/
              sz9gW0hTQsLGlrnLDJbH7AtcBiK7iltDNHCBfghBIYRBxr/kxx+/MtjfCWlKWKwU
              /wIDAQABo1MwUTAdBgNVHQ4EFgQUjqw+fFV1XHm21/jwANQ407RhVogwHwYDVR0j
              BBgwFoAUjqw+fFV1XHm21/jwANQ407RhVogwDwYDVR0TAQH/BAUwAwEB/zANBgkq
              hkiG9w0BAQsFAAOCAQEAsa4AjCqBspPlZdNhGLpX+jigKJ9klV7XZAi5C7CbM1uj
              SjztbNIbycxQsGjduJgxzhXCUUkPZWsOqb5/5j+/PrSGWRpDc1Lct34wDWYP2gHJ
              cszQ+J1JTkPTs7/ZEnutcWpl3WH72w/Rp156fSK6Xi+D7mbOn2ubv92d4YO3aXHE
              3r6BDx824lhQ+BQgReWBsMmx8VG8vDu52LlRIUAGbIPENmgG3LqU36NVdqAzAlTI
              bRsHxPALQWZlX/VZvng66vJEXPhY1en4BztN8Lfxp+MGHykQOCZBton0bndIjF4b
              A+lSMYUkbYS7WwCgWKxF3FF2d/XGHCkjPUKmf5CmLg==
              -----END CERTIFICATE-----
              -----BEGIN PRIVATE KEY-----
              MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyxsDRUHRZOKS5
              8E5VpQK0gPJVD22SczvLFWD6klzvMD+dVa81tn6xXqVWLUT3A9woO8fV13032YA4
              r0TX8oo2Zrz6jlDXSTU5INo9HnRodjqK6QU4mIZozQvcVWyYk7qLRRdnVnO2Q8cz
              fEQTquYFi+AFgJ4dKYw1at2H9Tw+e17Z0qfkYiY4vPIr8J5kmmIT8dewMZjrwF50
              BBIKVmdMxA2kzpHKeZufu1GsJ/ppQOEWeatwd5rdaV0jl0nM97ZQPSTcQF079L/I
              DpsRnn+zP2BbSFNCwsaWucsMlsfsC1wGIruKW0M0cIF+CEEhhEHGv+THH78y2N8J
              aUpYrBT/AgMBAAECggEAGs6IrRo2SAahVKw+4sK6dBx9udl1YadbyOjswMXfn5IJ
              h+sIObKirq/1dMWW+L8gbPwBzAPi59P6UQWe+g6JQP0Iyz05y/5TN7zAXLfLVrqb
              rqagPMtKJD7Sz3gTr5E/QJDcoIcrFKJ3JTY18wkGMsC1l72gd9j6CCx9CVzxaqDO
              0U1OzmZphKLkneIzCK+f644QmeK6sA1nOjpeudoK7o/Trm9/vBxZ2QuNjjw3LuOB
              U5DdDwoWiD5ovcQBgHm4Y6XlAJkxDZtIYG2RU8GbICbMqc3nWqu11Q22+lCUAX5z
              /twHBK8wxu3DpJNIVzUc+roIWb4W6BsJwO5W/OJjOQKBgQDm23jeBxdp7jpbwsOW
              kNyhbgRTPteI3h+Il4CdR+ExIzCjAZqOPA6lQmcXwMMdUB6eXzPIwyYAi/8IJ4Wt
              JX4HuPbAOCEj68jqvGphF9CH7zq1PFdEpqGjDQeUej9ZZMfroDrGNcpahzoV8yov
              HNVDBEB9hJA8S/qyaWx890NBdQKBgQDGPzayCSEpJ9NxN18uJpCx823QGGFQ3316
              MtseKU/cTEFtwbrZBpZdJnSyH3L/j318BopN53XFtbZFJCrZGvPCTTtHUj1Y+FHQ
              hStbkp6cXDVPVB9RpjxFQOwffW81KbQYcV4nRuj5ZeXUmJJyjKFW+LV03UOb2nFx
              RPAeIbtaIwKBgQCZpYSiMRISPK22mL/YG/3bqv9R8Ec/HqbaIAtHoqlsLMGYG98j
              vzD4KGO42WCCx+o4+Z/bhJZsUsCgSr2baZKhzSbc8/6Ki8kjAdfDWzg84KmwKcLj
              PAvkGy3qUhqLgpnUZsX3WaGd8tZj+X0f8g62FcReRbZBi0gFKkk8Os0WaQKBgDzH
              0sAg9m7EzBnxDRh8MG6uoKNlZijCbJkTkISdy+NR6dl5xQyW7XDfwnV+GObrmmB1
              LOAXr88PGDP4k75+ee+/eAY026Q0dfkFazanLEPqLVoGA5gn7GCbOAmrjnXxNEsu
              LtzB69nS+PUGVhgSr8CXfiK3V+wnvBIrPacvVl6bAoGBALsM7g2E064AKg1v7IJt
              QtCg0ILmMu7+5KjmEPqXPOwhaRYN4Nw91b+EGjGbLKEeCABoitJ+Bpj68pKtkw19
              2D2qmPlb2qdGCUYZUDLSbliveI2q0byQcMvoonHbZaQ3UfLzRzaSNQxOUgU+BXGJ
              v40vQ1XaeKlVtXuzhsmJ4gZw
              -----END PRIVATE KEY-----
            claims:
            - attr: acr
            - attr: sub
            hdr_name: jwt
  1. Create the IBM Application Gateway configuration configmap.
kubectl apply -f test_config.yaml
  1. Paste the following into a file named deployment.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
  labels:
    app: test
    name: test
  annotations:
    ibm-application-gateway.security.ibm.com/env.LANG: en
    ibm-application-gateway.security.ibm.com/configuration.test.type: configmap
    ibm-application-gateway.security.ibm.com/configuration.test.name: test-config
    ibm-application-gateway.security.ibm.com/configuration.test.dataKey: config
    ibm-application-gateway.security.ibm.com/configuration.test.order: "1"
    ibm-application-gateway.security.ibm.com/deployment.image: ibmcom/ibm-application-gateway:20.09.0
    ibm-application-gateway.security.ibm.com/deployment.imagePullPolicy: IfNotPresent
    ibm-application-gateway.security.ibm.com/service.port: "30441"
spec:
  selector:
    matchLabels:
      app: test
      name: test
  replicas: 1
  template:
    metadata:
      labels:
        app: test
        name: test
    spec:
      containers:
      - name: test
        image: ibmcom/ibm-application-gateway-demo-resource-server:20.09.0
        imagePullPolicy: IfNotPresent
  1. Create the deployment.
kubectl apply -f deployment.yaml
  1. Check the deployment. There should be a deployment application named “test” and a pod with a prefix of “test” that has 2 running containers.
kubectl get all

NAME                                                    READY   STATUS    RESTARTS   AGE
pod/ibm-application-gateway-operator-5b55989d98-w22n9   1/1     Running   0          12m
pod/test-7797447ccf-zg7nq                               2/2     Running   0          34s

NAME                                                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
service/ibm-application-gateway-injector-webhook-svc    ClusterIP   10.105.52.14    <none>        443/TCP             10m
service/ibm-application-gateway-operator-metrics        ClusterIP   10.97.147.42    <none>        8383/TCP,8686/TCP   12m
service/kubernetes                                      ClusterIP   10.96.0.1       <none>        443/TCP             32m
service/test-ibm-application-gateway-sidecar-svc2tmd4   NodePort    10.111.179.97   <none>        8443:30441/TCP      34s

NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ibm-application-gateway-operator   1/1     1            1           12m
deployment.apps/test                               1/1     1            1           34s

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/ibm-application-gateway-operator-5b55989d98   1         1         1       12m
replicaset.apps/test-7797447ccf                               1         1         1       34s
  1. Get the Minikube service URL.

Note: The service to use is the service with the name "test-ibm-application-gateway-sidecar" plus a random generated suffix.

minikube service test-ibm-application-gateway-sidecar-svc2tmd4 --url

Starting tunnel for service test-ibm-application-gateway-sidecar-svc2tmd4.
|-----------|-----------------------------------------------|-------------|------------------------|
| NAMESPACE |                     NAME                      | TARGET PORT |          URL           |
|-----------|-----------------------------------------------|-------------|------------------------|
| default   | test-ibm-application-gateway-sidecar-svczt6fm |             | http://127.0.0.1:53402 |
|-----------|-----------------------------------------------|-------------|------------------------|
http://127.0.0.1:53402
❗  Because you are using docker driver on Mac, the terminal needs to be open to run it.
  1. Leave the console as is and using a browser access the demo URL. This is the URL returned in the previous step with /demo-local appended. Make sure its https rather than http.

For example:

https://127.0.0.1:53402/demo-local
  1. The demo page is shown.

This page includes the following pieces that have been added by the IBM Application Gateway:

  • A JWT header has been added
  • The AZN-CRED-REGISTRY-ID header has been added
  • The MECH-INFO header has been added
  • The JWT has been extracted

Demo Application

  1. Exit the Minikube service by pressing ctrl-c in the shell.

  2. Delete the test application.

kubectl delete -f deployment.yaml
  1. Check the deployment and service are removed.
kubectl get all

NAME                                                    READY   STATUS    RESTARTS   AGE
pod/ibm-application-gateway-operator-5b55989d98-w22n9   1/1     Running   0          30m

NAME                                                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
service/ibm-application-gateway-injector-webhook-svc    ClusterIP   10.105.52.14    <none>        443/TCP             30m
service/ibm-application-gateway-operator-metrics        ClusterIP   10.97.147.42    <none>        8383/TCP,8686/TCP   32m
service/kubernetes                                      ClusterIP   10.96.0.1       <none>        443/TCP             52m

NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ibm-application-gateway-operator   1/1     1            1           32m

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/ibm-application-gateway-operator-5b55989d98   1         1         1       32m
  1. Cleanup.
kubectl delete -f test_config.yaml
kubectl delete -f webhook.yaml
kubectl delete -f webhook_service.yaml
kubectl delete -f operator.yaml
kubectl delete -f crd.yaml
kubectl delete -f service_account.yaml
kubectl delete -f rbac.yaml
kubectl delete secrets/ibm-application-gateway-webhook-certs
  1. Stop Minikube.
minikube stop