nats-io / k8s

NATS on Kubernetes with Helm Charts
Apache License 2.0
446 stars 302 forks source link

Provide Authentication Examples #859

Closed justinrush closed 7 months ago

justinrush commented 7 months ago

What motivated this proposal?

The previous version of the helm chart was a bit easier to understand and there were several clear examples of how to set up common authentication mechanisms such as mTLS for client to NATS. The new chart is very complicated and I've either missed the breadcrumbs or there are none related to auth.

I just want to use the newest version of the helm chart but the auth section of values appears to be ignored, so I'm guessing I'm supposed to hack at one of those merge statements scattered about, but I have no idea where or what to put.

What is the proposed change?

Provide a clear example of how to enable client mTLS including remapping the SAN to the user.

Who benefits from this change?

People that use authentication for NATS and want to upgrade to this new chart.

What alternatives have you evaluated?

I've read through documentation and I have an idea for how to do this, but I'm not positive. I ran out of time today but I will try tomorrow and post what worked for when someone has time to update docs.

caleblloyd commented 7 months ago

In general, follow the NATS documentation and put it into config.merge as YAML. And it'll get merged right into your NATS config file.

So, for example, anything in here can get put under config.merge as YAML: https://docs.nats.io/running-a-nats-service/configuration

caleblloyd commented 7 months ago

Here is a concrete example following this tutorial:

https://docs.nats.io/running-a-nats-service/configuration/securing_nats/auth_intro/tls_mutual_auth#mapping-client-certificates-to-a-user

Under Mapping Client Certificates To A User, suppose you want the NATS Config:

tls {
  cert_file: "server-cert.pem"
  key_file:  "server-key.pem"
  ca_file:   "rootCA.pem"
  # Require a client certificate and map user id from certificate
  verify_and_map: true
}

authorization {
  users = [
    {user: "email@localhost"}
  ]
}

In helm that would be:

config:
  merge:
    tls:
      cert_file: "server-cert.pem"
      key_file:  "server-key.pem"
      ca_file:   "rootCA.pem"
      verify_and_map: true
    authorization:
      users:
      - user: "email@localhost"

Try it out, save that as values.yaml and run:

$ helm template -f values.yaml nats/nats -s templates/config-map.yaml
---
# Source: nats/templates/config-map.yaml
apiVersion: v1
data:
  nats.conf: |
    {
      "authorization": {
        "users": [
          {
            "user": "email@localhost"
          }
        ]
      },
      "http_port": 8222,
      "lame_duck_duration": "30s",
      "lame_duck_grace_period": "10s",
      "pid_file": "/var/run/nats/nats.pid",
      "port": 4222,
      "server_name": $SERVER_NAME,
      "tls": {
        "ca_file": "rootCA.pem",
        "cert_file": "server-cert.pem",
        "key_file": "server-key.pem",
        "verify_and_map": true
      }
    }

Now let's say you want to reference the TLS Certificate and TLS CA from pre-existing secrets. You can use config.nats.tls for the cert, and tlsCA for the CA. Change the values.yaml to:

tlsCA:
  enabled: true
  secretName: my-tls-ca
  key: ca.crt

config:
  merge:
    authorization:
      users:
      - user: "email@localhost"

  nats:
    tls:
      enabled: true
      secretName: my-tls-cert
      cert: tls.crt
      key: tls.key
      merge:
        verify_and_map: true

Try it out, save that as values.yaml and run:

$ helm template -f values.yaml nats/nats -s templates/config-map.yaml
---
# Source: nats/templates/config-map.yaml
apiVersion: v1
data:
  nats.conf: |
    {
      "authorization": {
        "users": [
          {
            "user": "email@localhost"
          }
        ]
      },
      "http_port": 8222,
      "lame_duck_duration": "30s",
      "lame_duck_grace_period": "10s",
      "pid_file": "/var/run/nats/nats.pid",
      "port": 4222,
      "server_name": $SERVER_NAME,
      "tls": {
        "ca_file": "/etc/nats-ca-cert/ca.crt",
        "cert_file": "/etc/nats-certs/nats/tls.crt",
        "key_file": "/etc/nats-certs/nats/tls.key",
        "verify_and_map": true
      }
    }

Now let's say you want to add the client credentials to the nats-box context using a pre-existing secret, use natsBox.contexts.default.tls. It'll already load the tlsCA because that is shared between nats and natsBox. Add the client cert:

natsBox:
  contexts:
    default:
      tls:
        secretName: email-at-localhost-cert
        cert: tls.crt
        key: tls.key

Try it out, append this to values.yaml and run:

$ helm template -f values.yaml nats/nats -s templates/nats-box/contexts-secret.yaml
---
# Source: nats/templates/nats-box/contexts-secret.yaml
stringData:
  default.json: |
    {
      "ca": "/etc/nats-ca-cert/ca.crt",
      "cert": "/etc/nats-certs/default/tls.crt",
      "key": "/etc/nats-certs/default/tls.key",
      "url": "nats://release-name-nats"
    }
justinrush commented 7 months ago

This was super helpful - that last one was exactly what I needed, thanks!

I think it would be helpful to add this to the readme for the chart, but knowing the new use of merge and how that works is good for me for now.

thanks again