# Introduction

### What is Vault-CRD?

Vault-CRD is a custom resource definition for holding secrets that are stored in HashiCorp Vault up to date with Kubernetes secrets.

The following Secret engines of Vault are supported:

* KV (Version 1)
* KV (Version 2)
* PKI

The following types of secrets can be managed by Vault-CRD:

* Docker Pull Secret (DockerCfg)
* Ingress Certificates
* JKS Key Stores


# How does Vault-CRD work?

### How the creation workflow works

![](/files/-LA_6deH3NBK9gW2Yyw0)

A) The Vault-CRD receives event for new Vault resources\
B) Vault-CRD requests secret from HashiCorp Vault\
C) Vault-CRD generates new Kubernetes Secret

### How the updating workflow works

![](/files/-LA_7DReQ7lPMMrOqosS)

1\) Vault-CRD has a scheduled task that looks to the Secrets generated by it\
2\) It compares the Kubernetes Secret with the HashiCorp Vault state and updates the Kubernetes Secret if  necessary


# Supported Secret Types

### KEYVALUE

The KEYVALUE-Type is made for synchronising Secrets stored in a KV Secret Engine with Kubernetes Secrets. For more details please see: [KEYVALUE](/supported-secret-types/secret-type-keyvalue)

### KEYVALUE2

The KEYVALUEV2-Type is made for synchronising Secrets stored in the new KV2 Secret Engine with Kubernetes Secrets. For more details please see: [KEYVALUE2](/supported-secret-types/secret-type-keyvaluev2)

### PKI

The PKI-Type works in combination with a HashiCorp Vault [PKI Secret Engine](https://www.vaultproject.io/docs/secrets/pki/index.html) and requests new certificates if the old ones are expired. For more details please see: [PKI](/supported-secret-types/secret-type-pki)

### PKIJKS

The PKIJKS-Type is the same as the PKI-Type, but in this case a Java Key Store is generated and saved as secret. For more details please see: [PKIJKS](/supported-secret-types/secret-type-pkijks)

### CERT

The CERT-Type is for saved TLS Certificates in a specific format in a simple KV Secret Engine. It can be used to hold Kubernetes Ingress Certificates up to date. E.g. The certificate changes after a specific time, then no change has to be made, only the certificate must be overwritten. For more details please see: [CERT](/supported-secret-types/secret-type-cert)

### CERTJKS

The CERTJKS-Type is the same as the CERT-Type, but in this case a Java Key Store is generated and saved as secret. For more details please see: [CERTJKS](/supported-secret-types/secret-type-certjks)

### DOCKERCFG

The DOCKERCFG-Type is made to share Docker Pull Secrets with Kubernetes by saving it in a specific format in the KV Secret Engine of Vault. For more details please see: [DOCKERCFG](/supported-secret-types/secret-type-dockercfg)

### PROPERTIES

The PROPERTIES-Type is for rendering property-files based on secrets stored in HashiCorp Vault in the mountpoints for kv-1 or kv-2. For more details please see: [PROPERTIES](/supported-secret-types/secret-type-properties)


# Secret Type - KEYVALUE

The KEYVALUE-Type is made for synchronising Secrets stored in a KV Secret Engine with Kubernetes Secrets.

{% hint style="warning" %}
It only supports simple Key-Value pairs and not nested Values.
{% endhint %}

### How To

First write some secrets to HashiCorp Vault:

```bash
$ vault write secret/test-secret key=value key1=value1
```

After this create the following Vault-Resource and apply it to Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-secret
spec:
  type: "KEYVALUE"
  path: "secret/test-secret"
```

Now you should see, that new Secret and the Vault resource are available:

```bash
$ kubectl get vault test-secret
NAME             AGE
test-secret      7d
```

```bash
$ kubectl get secret test-secret
NAME                                   TYPE                                  DATA      AGE
test-secret                            Opaque                                2         7d
```

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - KEYVALUEV2

The KEYVALUEV2-Type is made for synchronising Secrets stored in the new KV2 Secret Engine with Kubernetes Secrets.

### How To

First write some secrets to HashiCorp Vault:

```bash
$ vault kv put versioned/example key=value
```

After this create the following Vault-Resource and apply it to Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: versionedsecret
spec:
  path: "versioned/example"
  type: "KEYVALUEV2"
  versionConfiguration:
    version: 1
```

Now you should see, the new Secret and the Vault resource are available:

```
$ kubectl get vault versionedsecret
NAME                 AGE
versionedsecret      10m
```

```bash
$ kubectl get secret versionedsecret
NAME                                   TYPE                                  DATA      AGE
versionedsecret                        Opaque                                1    
```

### Configuration Options

The versionConfiguration in the Vault-Custom Resource Definition is optional. If no version is specified the latest version will be used and in case of a new version in Vault it will be synchronized automatically to Kubernetes.

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: versionedsecret
spec:
  path: "versioned/example"
  type: "KEYVALUEV2"
```

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - PKI

�The PKI-Type is made to connect to the PKI - Secrets Engine of [HashiCorp Vault](https://www.vaultproject.io/docs/secrets/pki/index.html). It generates certificates X.509 Certificates and refreshes them if they are near the expiration date.

### How To

First generate a PKI in Vault and create a rule to issue new certificates:

{% hint style="danger" %}
This is only a test pki, for info how to generate a more secure pki please read the manual of HashiCorp Vault!
{% endhint %}

```
$ vault secrets enable -path=testpki -description=testpki pki
$ vault secrets tune -max-lease-ttl=8760h testpki
$ vault write testpki/root/generate/internal \
      common_name=koudingspawn.de \
      ttl=500h
$ vault write testpki/roles/testrole \
      allowed_domains=*.koudingspawn.de \
      max_ttl=8760h
```

After this create the following Vault-Resource and apply it to Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-pki
spec:
  path: "testpki/issue/testrole"
  type: "PKI"
  pkiConfiguration:
    commonName: "vault.koudingspawn.de"
    ttl: "8h"

```

This issues a new certificate that is available in your Kubernetes secret resource. It's saved in the format that Ingress can use to read them as certificates. For more details on ingress configuration please see: <https://koudingspawn.de/advanced-ingress/>

```
$ kubectl get vault test-pki
NAME       AGE
test-pki   8d
```

```
$ kubectl get secret test-pki
NAME       TYPE      DATA      AGE
test-pki   Opaque    2         8d
```

```
$ kubectl get secret test-pki -o yaml
apiVersion: v1
data:
  tls.crt: <certificate>
  tls.key: <key>
kind: Secret
metadata:
  annotations:
    vault.koudingspawn.de/compare: 2018-04-13T22:38Z
    vault.koudingspawn.de/lastUpdated: 2018-04-14T00:31:42.889
  creationTimestamp: 2018-04-13T22:16:03Z
  name: test-pki
  namespace: default
  resourceVersion: "1791800"
  selfLink: /api/v1/namespaces/default/secrets/test-pki
  uid: 40eaddf8-3f68-11e8-8433-b2b7401505d0
type: Opaque
```

### Supported Values in pkiConfiguration

```yaml
pkiConfiguration:
  commonName: "vault.koudingspawn.de"
  altNames: ""
  ipSans: ""
  ttl: "8h"
```

For more information about the described fields please see the [API documentation](https://www.vaultproject.io/api/secret/pki/index.html#generate-certificate) of Vault.

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - PKIJKS

The PKIJKS-Type is the same as the [PKI-Type](/supported-secret-types/secret-type-pki). The only difference is that it converts the issued certificate into a Java Key Store.

### How TO

How to generate a PKI is documented by HashiCorp in their Secrets Engine documentation. For a short simple example please see the [How To section of PKi-Type.](/supported-secret-types/secret-type-pki#how-to)

After you have generated a PKI create the Vault resource in Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-pkijks
spec:
  path: "testpki/issue/testrole"
  type: "PKIJKS"
  pkiConfiguration:
    commonName: "localhost"
    ttl: "7m"
  jksConfiguration:
    password: "changeit"
```

Now you should see the Vault resource in Kubernetes and the newly generated secret:

```
$ kubectl get vault test-pkijks
NAME          AGE
test-pkijks   8d
```

```
$ kubectl get secret test-pkijks
NAME          TYPE      DATA      AGE
test-pkijks   Opaque    1         8d
```

The Java Key Store is saved by default in the key.jks field. It's possible to change the field via the jksConfiguration Object:

### jksConfiguration

```yaml
jksConfiguration:
  password: "changeit"
  alias: "main"
  keyName: "key.jks"
```

The field password defines the password that's used to secure the Key Store. The alias is for defining the name of the TLS-Certificate in the Key store and the key name is for specifying the save path in the secret.

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - CERT

The Certificate-Type is similar to a KEYVALUE-Type but the data has to be saved in a specific order. The reason for this is, that when you issue a new certificate from a PKI Secret Engine in Vault they are wrapped in a second data object.

### How To:

First generate or use an existing PKI. A documentation can be found at HashiCorps documentation page for Vault. Now issue a certificate, pipe it to a file and save it to a KV Secret Engine:

```
$ vault write -format=json testpki/issue/testrole common_name=test-url.example.com > data.json
$ vault write secret/test-url.example.com @data.json
```

Now you should see that the data is saved in a second data object:

```
{
  "request_id": "31773810-0506-cc95-ce44-20f6e9c45518",
  "lease_id": "",
  "lease_duration": 2764800,
  "renewable": false,
  "data": {
    "data": {
      "certificate": "CERTIFICATE",
      "issuing_ca": "ROOTCA",
      "private_key": "PRIVATEKEY",
      "private_key_type": "rsa",
      "serial_number": "SERIAL"
    },
    "lease_duration": 0,
    "lease_id": "",
    "renewable": false,
    "request_id": "1d26c72a-9179-168f-a371-0637034f816e",
    "warnings": null
  },
  "warnings": null
}
```

Now you can create the Vault resource in Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-cert
spec:
  path: "secret/test-url.example.com"
  type: "CERT"
```

This will generate the Vault resource and also the secret:

```
$ kubectl get vault test-cert
NAME        AGE
test-cert   8d
```

```
$ kubectl get secret test-cert
NAME        TYPE      DATA      AGE
test-cert   Opaque    2         8d
```

The data is stored to allow an Ingress to read it as tls. For more details on ingress configuration please see: <https://koudingspawn.de/advanced-ingress/>

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - CERTJKS

The CERTJKS-Type is the same as the [CERT-Type](/supported-secret-types/secret-type-cert). The only difference is that it converts the saved Certificate into a Java Key Store.

### How To

First please read the part of [CERT-TYPE](/supported-secret-types/secret-type-cert), because the Vault-CRD expects the Certificate in a specific format.

After this you can create the following Vault resource in Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-certjks
spec:
  path: "secret/test-url.example.com"
  type: "CERTJKS"
```

This will generate the Vault resource and also the secret:

```
$ kubectl get vault test-certjks
NAME           AGE
test-certjks   8d
```

```
$ kubectl get secret test-certjks
NAME           TYPE      DATA      AGE
test-certjks   Opaque    1         8d
```

By default the Key Store is saved in the key.jks path. You can change it with the [jksConfiguration](/supported-secret-types/secret-type-pkijks#jksconfiguration) as described in [PKIJKS](/supported-secret-types/secret-type-pkijks#jksconfiguration).

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - DOCKERCFG

The DOCKERCFG-Type is for syncing the Pull-Credentials for secured Docker repositories. The data has to be saved in a specific format inside a KV Secret Engine.

Based on your used Key Value Secret Engine please see the following instructions.

### How To for KV Engine V1:

As already described the Pull-Credentials must be saved in a specific format inside a KV Secret Engine:

```
$ vault write secret/gitlab-hub url=registry.gitlab.com username=username password=VERYSECUREPASSWORD email=email@test.com
```

After this you can apply the following Vault Resource to Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-dockercfg
spec:
  path: "secret/gitlab-hub"
  type: "DOCKERCFG"
```

Now you should see a Vault resource in Kubernetes and the created Docker Pull-Credentials:

```
$ kubectl get vault test-dockercfg
NAME             AGE
test-dockercfg   8d
```

```
$ kubectl get secret test-dockercfg
NAME             TYPE                      DATA      AGE
test-dockercfg   kubernetes.io/dockercfg   1         8d
```

### How To for KV Engine V2:

As already described the Pull-Credentials must be saved in a specific format inside a KV2 Secret Engine:

```
$ vault kv put secret/gitlab-hub url=registry.gitlab.com username=username password=VERYSECUREPASSWORD email=email@test.com
```

After this you can apply the following Vault Resource to Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: test-dockercfg
spec:
  path: "secret/gitlab-hub"
  type: "DOCKERCFG"
  dockerCfgConfiguration:
    type: "KEYVALUEV2"
    version: 1
```

Now you should see a Vault resource in Kubernetes and the created Docker Pull-Credentials:

```yaml
$ kubectl get vault test-dockercfg
NAME             AGE
test-dockercfg   8d
```

```
$ kubectl get secret test-dockercfg
NAME             TYPE                      DATA      AGE
test-dockercfg   kubernetes.io/dockercfg   1         8d
```

### Supported Values in dockerCfgConfiguration

```yaml
dockerCfgConfiguration:
  type: "KEYVALUEV2" or "KEYVALUE"   if not provided default: "KEYVALUE"
  version: 1                         if not provided default is latest
```

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Secret Type - PROPERTIES

The PROPERTIES-Type is for rendering property-files based on secrets stored in HashiCorp Vault in the mountpoints for kv-1 or kv-2.

### How To

First store some secrets in HashiCorp Vault:

```bash
$ vault write datasource/host host=localhost
$ vault kv put database/root username=root password=verysecure
```

After this create the following Vault-Resource and apply it to Kubernetes:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  name: properties-example
spec:
  type: "PROPERTIES"
  propertiesConfiguration:
    files:
      application.properties: |
        datasource.username={{ vault.lookupV2('database/root').get('username') }}
        datasource.password={{ vault.lookupV2('database/root').get('password') }}
        datasource.host={{ vault.lookup('datasource/host', 'host') }}
```

Now you should see, that the secret gets rendered and stored in Kubernetes and the Vault resource is also available:

```
$ kubectl get vault properties-example
NAME                  AGE
properties-example    10s
```

```
$ kubectl get secret properties-example
NAME                                   TYPE                                  DATA      AGE
properties-example                     Opaque                                1         9s
```

### Rendering Options

The following expressions are available for rendering secrets stored in HashiCorp Vault:

| Method                                               | returns      | Description                                                                                                                      |
| ---------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| vault.lookup(String path)                            | Java:HashMap | Looks inside a KV-1 Store for stored key-value pairs. The secrets are now available via .get('key')                              |
| vault.lookup(String path, String key)                | String       | Looks inside a KV-1 Store for stored key in key-value path.                                                                      |
| vault.lookupV2(String path)                          | Java:HashMap | Looks inside a KV-2 Store for stored key-value pairs. The secrets are now available via .get('key'). It uses the latest version. |
| vault.lookupV2(String path, String key)              | String       | Looks inside a KV-2 Store for stored key in key-value path. It uses the latest version.                                          |
| vault.lookupV2(String path, int version, String key) | String       | Looks inside a KV-2 Store for stored key in key-value path with a specific version.                                              |

### Change Adjustment Callback

For more details please see [Change Detection](/change-detection)!


# Change Detection

(Since 1.6.0)

To react on Secret Changes there is a Change Adjustment Callback that can be defined. If such Callback is defined a new rollout of a Deployment gets triggered when the secret is changed by Vault-CRD. This will then inject the new secret value and a reload of the secret can be enforced (e.g. start of new application context lookup in Spring Boot).

All secret types support this Change Adjustment via the following yaml snippet:

```yaml
apiVersion: "koudingspawn.de/v1"
kind: Vault
metadata:
  [...]
spec:
  [...]
  changeAdjustmentCallback:
    type: deployment
    name: nginx
```

In this case the deployment nginx (same namespace as Vault resource) gets restarted when the secret was modified.

| Field | Description                                                                   |
| ----- | ----------------------------------------------------------------------------- |
| type  | Resource Type that should be updated (Currently only deployment is supported) |
| name  | Name of the Resource that should be updated (rollout redo)                    |


# Install Vault-CRD

The following part describes how to install Vault-CRD inside a Cluster with enabled RBAC.

First you have to specify which authentication method you would like to use for Vault-CRD to access Vault. There are two supported methods:

1. [Static Vault Token generated in Vault](/install-vault-crd#static-vault-token)
2. [Kubernetes Service Account Authentication](/install-vault-crd#kubernetes-service-account-authentication)

### Static Vault Token

Create a file called policy.hcl with the following content:

```
path "testpki/issue/testrole" {
  capabilities = ["create", "read", "update"]
}

path "secret/*" {
  capabilities = ["read"]
}
```

This defines a new policy that has access to issue new Certificates in a testpki with role testrole and has read access to all secrets in the secret-mountpoint. To write this policy to HashiCorp Vault please run the following command:

```
$ vault write sys/policy/testpolicy policy=@policy.hcl
```

The policy is now available in Vault and has the name testpolicy.

Now you can generate the Vault Token, that has this new testpolicy assigned:

```
$ vault token create -policy=testpolicy -display-name=testtoken
Key                Value
---                -----
token              7b021d51-c4e8-5b28-e944-5dceb1ec5191
token_accessor     540957b0-0340-2c06-1546-7c28e682983f
token_duration     768h
token_renewable    true
token_policies     [default testpolicy]
```

Now the value of the token-key is the token, that is required to deploy Vault-CRD.

#### Deploy Vault-CRD

At the end of the deploy/rbac.yaml-file is the Deployment of Vault-CRD with two environment variables. Please change the values of them to your personal settings. e.g:

```yaml
        - name: KUBERNETES_VAULT_URL
          value: "http://localhost:8080/v1/"
        - name: KUBERNETES_VAULT_TOKEN
          value: "7b021d51-c4e8-5b28-e944-5dceb1ec5191"
```

{% hint style="warning" %}
Please don't forget the /v1/ path at the end of the Kubernetes Vault Url
{% endhint %}

Now you can deploy the rbac file with the following command:

```
$ kubectl apply -f https://raw.githubusercontent.com/DaspawnW/vault-crd/master/deploy/rbac.yaml
```

### Kubernetes Service Account authentication

First please create a Service Account and a ClusterRoleBinding to the Service Account to generate a reviewer JWToken. Therefore please apply the following Kubernetes changes:

```bash
kubectl create serviceaccount vault-auth

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: role-tokenreview-binding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: vault-auth
  namespace: default
EOF
```

Now you can enable the Kubernetes authentication method and use the generated Service Account to configure the reviewer handling. This allows Vault to verify the JWToken used by Vault-CRD to authenticate.

{% hint style="info" %}
If you work with a Mac please replace base64 -d with base64 -D
{% endhint %}

```bash
$ vault auth enable kubernetes

$ vaultSecretName=$(kubectl get serviceaccount vault-auth -o json | jq '.secrets[0].name' -r)
$ kubectl get secret $vaultSecretName -o json | jq '.data["ca.crt"]' -r | base64 -d > ca.crt
$ vault write auth/kubernetes/config \
    token_reviewer_jwt="$(kubectl get secret $vaultSecretName -o json | jq .data.token -r | base64 -d)" \
    kubernetes_host=https://127.0.0.1 \
    kubernetes_ca_cert=@ca.crt
```

The last step is to generate a policy (please see the Static Vault Token example) and generate a vault role that binds the secret for the Service Account to the policy:

```
vault write auth/kubernetes/role/vault-auth \
    bound_service_account_names=vault-crd-serviceaccount \
    bound_service_account_namespaces=vault-crd \
    policies=testpolicy \
    ttl=1h
```

#### Deploy Vault-CRD

At the end of the deploy/rbac.yaml-file is the Deployment of Vault-CRD with two environment variables. By default Vault-CRD is configured to use Static Vault Tokens. Please replace the values with the following information:

```yaml
        - name: KUBERNETES_VAULT_URL
          value: "http://localhost:8080/v1/"
        - name: KUBERNETES_VAULT_ROLE
          value: "vault-auth"
        - name: KUBERNETES_VAULT_AUTH
          value: "serviceAccount"
```

{% hint style="warning" %}
Please don't forget the /v1/ path at the end of the Kubernetes Vault Url
{% endhint %}

Now you can deploy the rbac file with the following command:

```
$ kubectl apply -f https://raw.githubusercontent.com/DaspawnW/vault-crd/master/deploy/rbac.yaml
```

### Configuration of Vault-CRD

The following environment variables can be changed to configure Vault-CRD

| Variable                                     | Description                                                                                                                                                                                                            | Default Value |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| �KUBERNETES\_VAULT\_URL                      | Please specify here the URL to your Vault installation. Don't forget to set the /v1/ path                                                                                                                              |               |
| �KUBERNETES\_VAULT\_TOKEN                    | Token with access to the resources that Vault-CRD shares from Vault to Kubernetes.                                                                                                                                     |               |
| KUBERNETES\_VAULT\_ROLE                      | If you use the Service Account approach for Vault authentication please specify here the Vault role. In the example above it's vault-auth.                                                                             |               |
| KUBERNETES\_VAULT\_AUTH                      | Specifies the used authentication method the following values are allowed: token \| serviceAccount                                                                                                                     | token         |
| KUBERNETES\_VAULT\_PATH                      | Please specify here the Vault auth path to be used.                                                                                                                                                                    | kubernetes    |
| �KUBERNETES\_INTERVAL                        | Specifies the refresh interval in **seconds**. In this interval Vault-CRD will check if something has changed in Vault that must be updated in Kubernetes.                                                             | 60            |
| KUBERNETES\_JKS\_DEFAULT\_ALIAS              | Specifies the default alias, where the certificate will be placed in a Java Key Store. Can be overwritten by specifying one in the [JKS Configuration](/supported-secret-types/secret-type-pkijks#jksconfiguration).   | main          |
| KUBERNETES\_JKS\_DEFAULT\_PASSWORD           | Default Password that encrypts the Java Key Store. Can be overwritten by specifying one in the [JKS Configuration](/supported-secret-types/secret-type-pkijks#jksconfiguration).                                       | changeit      |
| �KUBERNETES\_JKS\_DEFAULT\_SECRET\_KEY\_NAME | Specifies the default key name inside the generated secret where the keystore is placed. Can be overwritten by specifying one in the [JKS Configuration](/supported-secret-types/secret-type-pkijks#jksconfiguration). | key.jks       |


# Self Signed Certificates

This tutorial requires a Vault-CRD Version newer then 1.4.3

To use self signed certificates it's required to add to the main cacerts keystore the self signed certificate or the better solution is to add the root certificate of the self signed certificate.

{% hint style="info" %}
For security reasons, I will not provide a way to ignore invalid certificates.
{% endhint %}

To build a Docker Image that contains a Self Signed Certificate we will use a Docker Image Pipeline. This Pipeline will take the default cacerts file from openjdk:8, add our self-signed certificate and afterwards add this certificate to our cacerts keystore.

```
FROM openjdk:8 AS BUILD

COPY cert.pem /additional_certs/cert.pem
RUN yes | keytool -importcert -alias selfsignedroot -keystore /usr/local/openjdk-8/jre/lib/security/cacerts -storepass changeit -file /additional_certs/cert.pem
```

The last step is to add the edited cacerts keystore to vault-crd. Please replace in the FROM section the Docker Image Tag with the version you are planning to use:

```
FROM daspawnw/vault-crd:1.5.0

COPY --from=BUILD /usr/local/openjdk-8/jre/lib/security/cacerts /etc/ssl/certs/java/cacerts
```

Here the full example

```
FROM openjdk:8 AS BUILD

COPY cert.pem /additional_certs/cert.pem
RUN yes | keytool -importcert -alias selfsignedroot -keystore /usr/local/openjdk-8/jre/lib/security/cacerts -storepass changeit -file /additional_certs/cert.pem

FROM daspawnw/vault-crd:1.4.3

COPY --from=BUILD /usr/local/openjdk-8/jre/lib/security/cacerts /etc/ssl/certs/java/cacerts
```


# Enable Admission Webhook

The Admission Webhook can perform before applying the change a validation to see if the secret would get created correct without an exception that the secret is not accessible by Vault-CRD:

```
$ kubectl apply -f dockercfg-error.yml
Error from server: error when creating "dockercfg-error.yml": admission webhook "validate.vault.koudingspawn.de" denied the request: Couldn't load secret from vault path blub/docker-hub
```

### Configure Admission Webhook

The Admission Webhook can be applied by editing the deploy/rbac.yaml file. There are multiple lines commented out that configure the server to serve traffic on HTTPS.

The initContainer in this block simply converts the tls.crt and tls.key into a keystore. As Vault-CRD is written in Java it has to deal with keystores. The initContainer simply takes over this task to convert the pem encoded cert and key into a valid p12-Format.

Additionally there is a Secret called vault-crd-tls, this is an example secret that contains a tls.crt and a tls.key, these are the secrets used for serving HTTPS and receive Admission Webhook Requests form the APIServer. You can simply replace them with self signed certificates. The certificates must be valid for the service defined in "deploy/admission-webhook.yaml".

By default this is vault-crd, so it should be valid for:

* vault-crd.vault-crd
* vault-crd.vault-crd.svc

In case you have another name for the service you should name it with \<service-name>.\<namespace-name> and \<service-name>.\<namespace-name>.svc.

Afterwards please manipulate also the deploy/admission-webhook.yaml file. There replace the caBundle with the ca certificate to allow the APIServer to validate if the certificate is valid. In case you don't have a certificate chain you can also set here the certificate file as caBundle value.


