The recommended approach for installing Contrast agents in Kubernetes environments is via our Agent Operator. You can find the documentation for this here: Agent Operator (Kubernetes operator).
The following steps detail how to install agents in a Kubernetes environment manually and should only be used if installing the Agent Operator is not possible
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.yamland 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.yamland 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