# How to format tls certs in .yaml for Grafana datasource provisioning?

**URL:** <https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779>\
**Category:** Configuration\
**Tags:** provisioning\
**Created:** [May 29, 2018, 6:05pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779 "2018-05-29T18:05:23Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![ctote](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/ctote/32/2282_2.png) [@ctote](https://community.grafana.com/u/ctote)\
**Post date:** [May 29, 2018, 6:05pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/1 "2018-05-29T18:05:24Z")

</div>

We’re trying to mimic the settings in the UI for datasource provisioning in our .yaml. However, we’re consistently getting errors:

`"Failed to parse TLS CA PEM certificate"`

We’ve tried (a) without the `-----BEGIN CERTIFICATE-----`, (b) a copy paste of the certificate, and (c) removing all `\n`.

Our .yaml has the following format:

```
secureJsonData:
     tlsCACert: "-----BEGIN CERTIFICATE-----
     MII[...]Lz
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MII[..]d4=
-----END CERTIFICATE-----"
     tlsClientCert: "-----BEGIN CERTIFICATE-----
MII[..]c+g==
-----END CERTIFICATE-----"
     tlsClientKey: "-----BEGIN RSA PRIVATE KEY-----
MI[..]6Kd
-----END RSA PRIVATE KEY-----"
```

---

<div class="post-metadata">

**Author:** ![ctote](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/ctote/32/2282_2.png) [@ctote](https://community.grafana.com/u/ctote)\
**Post date:** [June 6, 2018, 10:08pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/2 "2018-06-06T22:08:32Z")

</div>

Would like to make a slight bump on this – could we get some guidance on what format the .yaml expects when including our certificates / keys?

---

<div class="post-metadata">

**Author:** ![jangaraj](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/jangaraj/32/39197_2.png) [@jangaraj](https://community.grafana.com/u/jangaraj)\
**Post date:** [June 6, 2018, 10:36pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/3 "2018-06-06T22:36:56Z")

</div>

You can use test data as an example:

> <https://github.com/grafana/grafana/blob/5c30643f6e2576262f1de8bfe342b70b170626a6/pkg/services/provisioning/datasources/testdata/all-properties/all-properties.yaml#L21-L24>

---

<div class="post-metadata">

**Author:** ![wrosscopeeko](https://avatars.discourse-cdn.com/v4/letter/w/47e85d/32.png) [@wrosscopeeko](https://community.grafana.com/u/wrosscopeeko)\
**Post date:** [June 8, 2018, 5:24pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/4 "2018-06-08T17:24:10Z")

</div>

For anyone else who encounters this - it looks like it’s related to the YAML formatting rather than the key. i got it to work looking like:

```auto
  jsonData: 
    tlsAuthWithCACert: true
  secureJsonData: 
    tlsCaCert: | 
      -----BEGIN CERTIFICATE-----
      line1
      line2
      .....
      ......
      -----END CERTIFICATE-----

```

---

<div class="post-metadata">

**Author:** ![ctote](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/ctote/32/2282_2.png) [@ctote](https://community.grafana.com/u/ctote)\
**Post date:** [June 8, 2018, 7:47pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/5 "2018-06-08T19:47:11Z")

</div>

Thanks @wrosscopeeko – would be super if someone from Grafana could update the docs to be better aligned with this example.

---

<div class="post-metadata">

**Author:** ![jrran64](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@jrran64](https://community.grafana.com/u/jrran64)\
**Post date:** [May 4, 2020, 7:16pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/6 "2020-05-04T19:16:00Z")

</div>

What documentation from Grafana says xyz format is required for certificates. I see none.

---

<div class="post-metadata">

**Author:** ![jangaraj](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/jangaraj/32/39197_2.png) [@jangaraj](https://community.grafana.com/u/jangaraj)\
**Post date:** [May 5, 2020, 5:21am UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/7 "2020-05-05T05:21:39Z")

</div>

So it is good opportunity on your side to fix it. Doc is maintained via GitHub and it provides also link, where you can edit&propose doc change:

 ![image](https://us1.discourse-cdn.com/grafana/original/2X/d/dad2d3cdd1dfb3601c49061210ea97d7802184e6.png)

---

<div class="post-metadata">

**Author:** ![jrran64](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@jrran64](https://community.grafana.com/u/jrran64)\
**Post date:** [May 6, 2020, 3:26pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/8 "2020-05-06T15:26:12Z")

</div>

Sure, once I find the answer for the questions I have.

---

<div class="post-metadata">

**Author:** ![jangaraj](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/jangaraj/32/39197_2.png) [@jangaraj](https://community.grafana.com/u/jangaraj)\
**Post date:** [May 6, 2020, 7:39pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/9 "2020-05-06T19:39:33Z")

</div>

PEM formatted string?

> PEM is defined in RFCs [1421](https://tools.ietf.org/html/rfc1421) through [1424](https://tools.ietf.org/html/rfc1424), this is a container format that may include just the public certificate (such as with Apache installs, and CA certificate files `/etc/ssl/certs` ), or may include an entire certificate chain including public key, private key, and root certificates. Confusingly, it may also encode a CSR (e.g. as used [here](https://jamielinux.com/docs/openssl-certificate-authority/create-the-intermediate-pair.html)) as the PKCS10 format can be translated into PEM. The name is from [Privacy Enhanced Mail (PEM)](https://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail), a failed method for secure email but the container format it used lives on, and is a base64 translation of the x509 ASN.1 keys.

Cited from [certificate - What is a Pem file and how does it differ from other OpenSSL Generated Key File Formats? - Server Fault](https://serverfault.com/questions/9708/what-is-a-pem-file-and-how-does-it-differ-from-other-openssl-generated-key-file)

That PEM string can be multiline string, so then you need to know how to write multiline string in YAML. That also has own rules [https://yaml-multiline.info/](https://yaml-multiline.info/)

---

<div class="post-metadata">

**Author:** ![thanosegw](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/thanosegw/32/17528_2.png) [@thanosegw](https://community.grafana.com/u/thanosegw)\
**Post date:** [July 19, 2021, 12:20pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/10 "2021-07-19T12:20:51Z")

</div>

Thank @wrosscopeeko for providing the solution to this (wrong documentation) issue on how to add the CA.

Maybe we should add also here for future reference to other users that the CA on your example has a single white character added on all the CA lines.

It is not easy to understand from the text that the user needs to add also whitespaces until that point.

To add complete description:

```auto
# config file version
apiVersion: 1

sioning/#data-sources
datasources:
  - name: Sample
    # <string, required> datasource type. Required
    type: prometheus
    # <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
    access: proxy
    # <int> org id. will default to orgId 1 if not specified
    orgId: 1
    basicAuth: true
    # <string> basic auth username, if used
    basicAuthUser: {{ user }}
    # <bool> enable/disable with credentials headers
    withCredentials: true
    # <bool> mark as default datasource. Max one per org
    isDefault: true
    # <map> fields that will be converted to json and stored in json_data
    jsonData:
      graphiteVersion: "1.1"
      tlsAuth: false
      tlsAuthWithCACert: true
      oauthPassThru: true
    # <string> json object of data that will be encrypted.
    secureJsonData:
      tlsCACert: |2
        -----BEGIN CERTIFICATE-----
        line 1
        line 2
        .
        .
        .
        -----END CERTIFICATE-----

```

The interesting part to notice here is `|<int>` this indicates how many white space lines is expected after the pipe. By default (ommited) is 1. Anything above that (if desired) needs to be defined.

In case that someone wants to add the CA / CRT or KEY through Ansible the user can use Jinja2 with templates.

I managed to achieve it by loading the CA / CRT and KEY into vars and then adding it on the file.

Sample of code:

```auto
- name: Append 8 white space characters on ca                                                                                                                                                                                                  
  register: grafanaCa
  ansible.builtin.shell:
    cmd: "sed 's/^/ /g' {{ role_path }}/files/{{ grafana.cert.files.ca }}"
  no_log: true

```

And then on the relevant file that the user wants to update:

```auto
datasources:
  # <string, required> name of the datasource. Required
  - name: Prometheus
    # <string, required> datasource type. Required
    type: prometheus
    # <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
    access: proxy
    # <int> org id. will default to orgId 1 if not specified
    orgId: 1
    # <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
    url: https://{{ hostname }}:{{ prometheus.conf.port }}
    # <string> database user, if used
    user:
    # <string> database name, if used
    database:
    # <bool> enable/disable basic auth
    basicAuth: true
    # <string> basic auth username, if used
    basicAuthUser: {{ user }}
    # <bool> enable/disable with credentials headers
    withCredentials: true
    # <bool> mark as default datasource. Max one per org
    isDefault: true
    # <map> fields that will be converted to json and stored in json_data
    jsonData:
      graphiteVersion: "1.1"
      tlsAuth: true
      tlsAuthWithCACert: true
      oauthPassThru: true
    # <string> json object of data that will be encrypted.
    secureJsonData:
      tlsCACert: |2
{{ grafanaCa.stdout }}
      tlsClientCert: |2
{{ grafanaCrt.stdout }}
      tlsClientKey: |2
{{ grafanaKey.stdout }}

```

Hope this helps someone else as I spent way too much time trying to figure it out…

---

<div class="post-metadata">

**Author:** ![pmph](https://avatars.discourse-cdn.com/v4/letter/p/da6949/32.png) [@pmph](https://community.grafana.com/u/pmph)\
**Post date:** [November 10, 2021, 4:32pm UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/11 "2021-11-10T16:32:56Z")

</div>

Spent the whole afternoon bashing my head against this… Thanks @thanosegw, you’re awesome!

My solution for using a local cert on the ansible controller:

```auto
{% set ca_file_contents = lookup('file', '/local/path/ca.crt') %}

datasources:
  - name: Prometheus
    ...
    secureJsonData:
      tlsCACert: |
        {{ ca_file_contents | replace("\n", "\n ") }}

```

---

<div class="post-metadata">

**Author:** ![Peret](https://avatars.discourse-cdn.com/v4/letter/p/7993a0/32.png) [@Peret](https://community.grafana.com/u/Peret)\
**Post date:** [July 20, 2023, 11:56am UTC](https://community.grafana.com/t/how-to-format-tls-certs-in-yaml-for-grafana-datasource-provisioning/7779/12 "2023-07-20T11:56:06Z")

</div>

Just another way of inserting tls secret data in **datasources-provisioning.yaml** , in case it can help somebody. In my case, I did not manage with ansible, Jinja2,… neither I wanted to install extra packages. I found an easy alternative way using ‘sed’ bash command (linux world).  
It consists in preprocessing the file before grafana is started. You can do that in the Dockerfile, with RUN, or as a script that runs before the default init script of the image, every time the container is started.  
In the latter case, as I did, I declared secrets, so I execute this code in the init script:

```auto
sed -i '/tlsClientCert/ r /run/secrets/gf_client_certificate' /etc/grafana/provisioning/datasources/datasources-provisioning.yaml
sed -i '/tlsCACert/ r /run/secrets/gf_ca_certificate' /etc/grafana/provisioning/datasources/datasources-provisioning.yaml
sed -i '/tlsClientKey/ r /run/secrets/gf_client_key' /etc/grafana/provisioning/datasources/datasources-provisioning.yaml

/run.sh

```

This is the initial content of _datasources-provisioning.yaml_ (secure json zone only):

```auto
    secureJsonData:
      httpHeaderValue1: "Token ${GF_DATASOURCE_INFLUXDB_TOKEN}"
      tlsCACert: |
      tlsClientCert: |
      tlsClientKey: |

```

With the certs and key files well formatted (8 blanks at the beginning of each line), it works nicely. Hope this adds another posible solution for somebody
