Install delegates with custom certificates
This topic explains how to install delegates with custom certificates. There are two aspects of custom certificates:
- A certificate for the delegate Java process, which makes connections to external systems.
- A certificate for the OS itself. With this certificate, if another process, such as a shell script, is spawned, it can access custom certificates.
In this topic we will do the following:
- Create a custom truststore.
- Create a secret.
- Add a volume mount to the
harness-delegate.yaml
file and provide it to the delegate Java process. - Add a volume mount to the
harness-delegate.yaml
file and configure the delegate container OS to have the certificates.
Harness recommends that you keep your existing Java KeyStore in place during the installation process. Updating the KeyStore may cause issues with your delegate.
For information on best practices for truststore creation, go to Java Keystore Best Practices.
Create a custom truststore
For instructions on how to create a custom truststore, go to Truststore override for delegates.
Create a secret from a truststore file
Use your custom truststore to create a secret:
kubectl create secret -n harness-delegate-ng generic mysecret --from-file harness_trustStore.jks=harness_trustStore.jks
Add a volume mount to the harness-delegate.yaml file
Modify the
harness-delegate.yaml
file to include a volume mount.Set the security context to provide the operator access to the mounted files:
securityContext:
fsGroup: 1001Update the
JAVA_OPTS
environment variable with information about your custom truststore:- name: JAVA_OPTS
value: "... -Djavax.net.ssl.trustStore=/cacerts/harness_trustStore.jks -Djavax.net.ssl.trustStorePassword=password"Replace the password placeholder with the password you gave your truststore.
noteYou can omit the specification of the
JAVA_OPTS
environment variable if you mount the secret to the same location as the default truststore and give it the same name. The JVM then applies the change automatically.Add the volume mount with read-only permission:
volumeMounts:
- mountPath: /cacerts
name: custom-truststore
readOnly: true
volumes:
- name: custom-truststore
secret:
secretName: mysecret
defaultMode: 400This concludes adding the certificates to the delegate process.
Add custom certificates to the delegate pod
In this section we will cover how to add certificates to the delegate pod so any command running on it has certificates installed. Let's take an example where you have cert1.crt
and cert2.crt
files that have custom certificates. Please note that it's not a necessary step if you do not intend to run commands directly on the pod that needs certificates to connect to external systems.
Mount these certificates to the delegate pod at
/etc/pki/ca-trust/source/anchors/
:volumeMounts:
- name: certs
mountPath : "/usr/local/share/ca-certificates/cert1.crt"
subPath: cert1.crt
- name: certs
mountPath : "/usr/local/share/ca-certificates/cert2.crt"
subPath: cert2.crtRun
update-ca-trust
usingINIT_SCRIPTS
:- name: INIT_SCRIPT
value: |-
update-ca-trustnoteThe delegate must be the root user.
securityContext:
allowPrivilegeEscalation: false
runAsUser: 0
Example harness-delegate.yaml
file
The following example harness-delegate.yaml
file includes the changes required to install a delegate with a custom certificate.
apiVersion: v1
kind: Namespace
metadata:
name: harness-delegate-ng
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: harness-delegate-ng-cluster-admin
subjects:
- kind: ServiceAccount
name: default
namespace: harness-delegate-ng
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Secret
metadata:
name: my-secret-account-token
namespace: harness-delegate-ng
type: Opaque
data:
ACCOUNT_SECRET: "XXXXXXXXXXXXXXXXXXXXXXXX"
---
# To learn how to proxy a delegate, go to [Configure delegate proxy settings](/docs/platform/2_Delegates/manage-delegates/configure-delegate-proxy-settings/)
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
harness.io/name: my-secret
name: my-secret
namespace: harness-delegate-ng
spec:
replicas: 1
selector:
matchLabels:
harness.io/name: my-secret
template:
metadata:
labels:
harness.io/name: my-secret
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "3460"
prometheus.io/path: "/api/metrics"
spec:
terminationGracePeriodSeconds: 600
restartPolicy: Always
securityContext:
allowPrivilegeEscalation: false
runAsUser: 0
containers:
- image: harness/delegate-immutable:22.07.75836.minimal
imagePullPolicy: Always
name: delegate
ports:
- containerPort: 8080
resources:
limits:
cpu: "0.5"
memory: "2048Mi"
requests:
cpu: "0.5"
memory: "2048Mi"
livenessProbe:
httpGet:
path: /api/health
port: 3460
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 2
startupProbe:
httpGet:
path: /api/health
port: 3460
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 15
envFrom:
- secretRef:
name: my-secret-account-token
env:
- name: JAVA_OPTS
value: "-Xms64M -Djavax.net.ssl.trustStore=/cacerts/harness_trustStore.jks -Djavax.net.ssl.trustStorePassword=mypassword"
- name: ACCOUNT_ID
value: XXXXXxxxxxx
- name: MANAGER_HOST_AND_PORT
value: https://qa.harness.io/gratis
- name: DEPLOY_MODE
value: KUBERNETES
- name: DELEGATE_NAME
value: my-secret
- name: DELEGATE_TYPE
value: "KUBERNETES"
- name: DELEGATE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: INIT_SCRIPT
value: |-
update-ca-trust
- name: DELEGATE_DESCRIPTION
value: ""
- name: DELEGATE_TAGS
value: ""
- name: NEXT_GEN
value: "true"
- name: CLIENT_TOOLS_DOWNLOAD_DISABLED
value: "true"
- name: LOG_STREAMING_SERVICE_URL
value: "https://qa.harness.io/gratis/log-service/"
volumeMounts:
- mountPath: /cacerts
name: custom-keystore
readOnly: true
- name: certs
mountPath : "/usr/local/share/ca-certificates/cert1.crt"
subPath: cert1.crt
- name: certs
mountPath : "/usr/local/share/ca-certificates/cert2.crt"
subPath: cert2.crt
volumes:
- name: custom-keystore
secret:
secretName: myjks
defaultMode: 400
---
apiVersion: v1
kind: Service
metadata:
name: delegate-service
namespace: harness-delegate-ng
spec:
type: ClusterIP
selector:
harness.io/name: my-secret
ports:
- port: 8080
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: upgrader-cronjob
namespace: harness-delegate-ng
rules:
- apiGroups: ["batch", "apps", "extensions"]
resources: ["cronjobs"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: my-secret-upgrader-cronjob
namespace: harness-delegate-ng
subjects:
- kind: ServiceAccount
name: upgrader-cronjob-sa
namespace: harness-delegate-ng
roleRef:
kind: Role
name: upgrader-cronjob
apiGroup: ""
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: upgrader-cronjob-sa
namespace: harness-delegate-ng
---
apiVersion: v1
kind: Secret
metadata:
name: my-secret-upgrader-token
namespace: harness-delegate-ng
type: Opaque
data:
UPGRADER_TOKEN: "XXXXXXXXXXXXXXXXXXXXXXXX"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: my-secret-upgrader-config
namespace: harness-delegate-ng
data:
config.yaml: |
mode: Delegate
dryRun: false
workloadName: my-secret
namespace: harness-delegate-ng
containerName: delegate
delegateConfig:
accountId: XXXXXXXXXXXXXXXXXXXXXXXX
managerHost: https://qa.harness.io/gratis
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
labels:
harness.io/name: my-secret-upgrader-job
name: my-secret-upgrader-job
namespace: harness-delegate-ng
spec:
schedule: "0 */1 * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 20
jobTemplate:
spec:
suspend: true
template:
spec:
serviceAccountName: upgrader-cronjob-sa
restartPolicy: Never
containers:
- image: us.gcr.io/qa-target/upgrader:1.0.0
name: upgrader
imagePullPolicy: Always
envFrom:
- secretRef:
name: my-secret-upgrader-token
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: my-secret-upgrader-config