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 11 fetches the latest Contrast Java agent.
# Add contrast sensor package
RUN curl --fail --silent --location "https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.contrastsecurity&a=contrast-agent&v=LATEST" -o /opt/contrast/contrast-agent.jar
Line 14 sets the JAVA_TOOL_OPTIONS to load our agent with the JVM. Also note the -Dcontrast.agent.java.standalone_app_name=spring-petclinic
parameter to set the application name as well as adding features like route coverage and session metadata that require this.
COPY --from=contrast /tmp/contrast /opt/contrast
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 Java 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/
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: 1.0
memory: 2Gi
limits:
cpu: 2.0
memory: 4Gi
# 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
env:
- name: CONTRAST__APPLICATION__NAME
value: "petclinic-k8s"
- name: CONTRAST__SERVER__NAME
value: "EKS-Core-Pod"
- name: CONTRAST__SERVER__ENVIRONMENT
value: "QA"
- name: CONTRAST_CONFIG_PATH
value: "/etc/contrast/contrast_security.yaml"
- name: CONTRAST__AGENT__LOGGER__STDOUT
value: "true"
- name: CONTRAST__AGENT__LOGGER__LEVEL
value: "INFO"
Optionally: these could also be defined via configmaps
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 and 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.standalone.appname=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 Maven
This deployment downloads the Contrast Java agent from Maven central 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__AGENT__JAVA__STANDALONE_APP_NAME value: Petclinic-k8s - name: CONTRAST__SERVER__TAGS value: k8s initContainers: - name: download-contrast image: appropriate/curl volumeMounts: - mountPath: /opt/contrast name: contrast-volume args: - "-L" - "https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.contrastsecurity&a=contrast-agent&v=LATEST" - "-o" - "/opt/contrast/contrast-agent.jar" volumes: - name: contrast-volume emptyDir: {} - name: contrast-security secret: secretName: contrast-security
Example C: 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__AGENT__JAVA__STANDALONE_APP_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