Java agent with Kubernetes

  • Updated
Contrast has released an Agent Operator for Kubernetes which can simplify the addition of Contrast agents into your environment. More information can be found here in our documentation.

This guide provides a working example of setting up and configuring the Contrast Java agent within a kubernetes environment.   This guide assumes you have basic working knowledge of git, docker and kubernetes.

Contents


Prerequisites

Setup a local kubernetes environment if you do not already have one available to you.  Below are a few of the available options.

Clone the following repo that will be used for this tutorial:

git clone https://github.com/Contrast-Security-OSS/demo-petclinic.git

Building and setting up the Java application's image w/Contrast


Inspect the Dockerfile found in the github example downloaded in the prerequisites, you should note a few sections where the Contrast agent is added:

Line 9 fetches the latest Contrast Java agent.

# Add contrast sensor package
COPY --from=contrast/agent-java:latest /contrast/contrast-agent.jar /opt/contrast/contrast.jar

Line 12 sets the JAVA_TOOL_OPTIONS to load our agent with the JVM.

ENV JAVA_TOOL_OPTIONS='-javaagent:/opt/contrast/contrast.jar'

For more details on adding the Contrast agent to your application/image. See our docker guide on the subject.


  1. In your terminal, navigate to the cloned repo's folder and run the following command to build the docker image.
docker build . -t spring-petclinic:k8s --no-cache
  1. Tag and push your image to a local or public repo.
docker tag spring-petclinic:k8s example/spring-petclinic:k8s
docker push example/spring-petclinic:k8s

Now this image can be used in the kubernetes deployment.

Setting up the Kubernetes environment

  1. Download the contrast_security.yaml and create a secret

YAML file should look like the following for our Java agent:

api: 
  url: http(s)://<dns>/Contrast
  api_key: <apiKey>
  service_key: <serviceKey>
  user_name: agent_<hashcode>@<domain>

Create a secret using kubectl

kubectl create secret generic contrast-security --from-file=./contrast_security.yaml

This secret can be used by all agents. So it is preferable to keep this generic and make all app level configuration changes with environment variables.

  1. Create the applications deployment file and add the contrast_security secret. This will mount the file under /etc/contrast/

Example deployment: https://github.com/Contrast-Security-OSS/demo-petclinic/blob/master/k8s/petclinic_deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: petclinic
spec: 
  replicas: 1
  selector: 
    matchLabels: 
      component: petclinic
  template:
    metadata:
      labels:
        component: petclinic
    spec:
      containers:
      - name: petclinic
        image: contrastsecuritydemo/spring-petclinic:k8s
        ports: 
          - containerPort: 8080
        envFrom:
          - configMapRef:
              name: contrast-config  
        # Volume Mount for contrast_security.yaml  
        volumeMounts:
        - name: contrast-security
          readOnly: false
          mountPath: "/etc/contrast"
        resources:
          requests:
            cpu: 0.5
            memory: 0.5Gi
          limits:
            cpu: 1.0
            memory: 1Gi
      # Volume from contrast-security secret     
      volumes:
      - name: contrast-security
        secret:
          secretName: contrast-security
  1. Add application level configurations to setup logging, pointer to the contrast_security.yaml and any desired name/environment updates. A full list of configurations options are provided in our documentation here

In this example we'll define these via a configmap

Create a file called contrast.properties with the same environment variables defined.

CONTRAST__SERVER__NAME=EKS-Core-Pod
CONTRAST__SERVER__ENVIRONMENT=qa
CONTRAST_CONFIG_PATH=/etc/contrast/contrast_security.yaml
CONTRAST__AGENT__LOGGER__STDOUT=true
CONTRAST__AGENT__LOGGER__LEVEL=INFO

Create the configmap

kubectl create configmap contrast-config --from-env-file=contrast.properties

Update the deployment file to reference the configmap.

    spec:
      containers:
      - name: petclinic
        image: contrastsecuritydemo/spring-petclinic:k8s
        ports: 
          - containerPort: 8080
        envFrom:
          - configMapRef:
              name: contrast-config
  1. Apply the deployment file
kubectl apply -f petclinic_deployment.yaml
  1. Finally configure a load balancer to expose the application.
kubectl expose deployment petclinic --type=LoadBalancer --name=petclinic-lb
  1. Check on the deployed application in kubernetes and access the site at External-IP/port 8080
kubectl get all

The sources for this example can be found on our github repo: demo-petclinic

 

Alternative Methods

 While adding the agent directly to the image is considered the best practice.  Not all users will have access or be able to do this.  For these situations we can download the contrast agent on-the-fly and copying this to a volume attached to the pod. 

The following deployments are examples of this. 

Example A: Fetching the Contrast Java agent from the Contrast UI

This deployment downloads the Contrast Java agent from the Contrast UI into a persistent volume utilizing an init container. 

Note: API authentication is redacted and will need to be updated along with the Contrast UI URL

---
apiVersion: v1
kind: ReplicationController
metadata:
  name: pet-rep
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: petclinic
    spec:
      containers:
      - name: petclinic
        image: arey/springboot-petclinic:latest
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /opt/contrast
          name: contrast-volume
        env:
        - name: JAVA_OPTS
          value: -Dserver.port=8080
        - name: JAVA_TOOL_OPTIONS
          value: "-javaagent:/opt/contrast/contrast-agent.jar -Dcontrast.application.name=Petclinic -Dserver.tags=k8s -Dcontrast.dir=/opt/contrast"
      initContainers:
      - name: download-contrast
        image: appropriate/curl
        volumeMounts:
        - mountPath: /opt/contrast
          name: contrast-volume
        args: 
        - "-o"
        - "/opt/contrast/contrast-agent.jar"
        - "https://app.contrastsecurity.com/Contrast/api/ng/ENTER_ORGID/agents/default/JAVA"
        - "-H"
        - "Authorization: redacted"
        - "-H" 
        - "API-Key: redacted" 
        - "-H"
        - "Accept: application/json"
      volumes:
      - name: contrast-volume
        persistentVolumeClaim:
          claimName: contrast-volume
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: contrast-volume
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 50Mi

 

Example B: Fetching the Contrast Java agent from Official Contrast docker image

This deployment copy the Contrast Java agent from the official Contrast java agent docker image into a temp volume utilizing an init container.  

---
apiVersion: v1
kind: ReplicationController
metadata:
  name: pet-rep
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: petclinic
    spec:
      containers:
      - name: petclinic
        image: arey/springboot-petclinic:latest
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: contrast-volume
          mountPath: /opt/contrast
        - name: contrast-security
          readOnly: false
          mountPath: "/etc/contrast"
        env:
        - name: JAVA_OPTS
          value: -Dserver.port=8080
        - name: JAVA_TOOL_OPTIONS
          value: "-javaagent:/opt/contrast/contrast-agent.jar -Dcontrast.config.path=/etc/contrast/contrast_security.yaml"
        - name: CONTRAST__APPLICATION__NAME
          value: Petclinic-k8s
        - name: CONTRAST__SERVER__TAGS
          value: k8s
      initContainers:
      - name: copy-contrast
        image: contrast/agent-java
        volumeMounts:
        - mountPath: /opt/contrast
          name: contrast-volume
        command: ["cp", "/contrast/contrast-agent.jar", "/opt/contrast/contrast-agent.jar"]
      volumes:
      - name: contrast-volume
        emptyDir: {}
      - name: contrast-security
        secret:
          secretName: contrast-security
          

 

 

Was this article helpful?

0 out of 0 found this helpful

Have more questions? Submit a request