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.
- Install Docker & kubernetes, follow instructions on https://docs.docker.com/docker-for-mac/install/
- Install and start Minikube, follow instructions on https://kubernetes.io/docs/tasks/tools/install-minikube/
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.
- 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
- 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
- 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.
- 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
- 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
- Apply the deployment file
kubectl apply -f petclinic_deployment.yaml
- Finally configure a load balancer to expose the application.
kubectl expose deployment petclinic --type=LoadBalancer --name=petclinic-lb
- 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