Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redis TLS Connection #12041

Open
3 tasks
mike-pisman opened this issue Nov 15, 2024 · 2 comments
Open
3 tasks

Redis TLS Connection #12041

mike-pisman opened this issue Nov 15, 2024 · 2 comments
Labels
bug Something isn't working status/stale This issue has not been updated recently

Comments

@mike-pisman
Copy link

mike-pisman commented Nov 15, 2024

Description

My Redis server requires client TLS certificates. As of now the authentik and helm chart support CA certificate but I also need to include private key and certificate.

In addition, according to redis python library docs, ssl_certfile and ssl_keyfile should be included - link

Error from logs:

Error while reading from authentik-redis-master.authentik.svc.cluster.local:6379:(1,'[SSL:TLSV13_ALERT_CERTIFICATE_REQUIRED] tlsv13 alert certificate required (_ssl.c:2559)')

Version and Deployment (please complete the following information):

  • authentik version: 2024.8.3
  • Deployment: Kubernetes helm chart

Additional context

I created a simple script to test if the lack of key and certificate would cause the same error and it does.

import redis
import pprint

try:
  redis_url = "rediss://:[email protected]:6379?ssl_cert_reqs=required&ssl_ca_certs=./ca.crt"
  r = redis.StrictRedis.from_url(redis_url, decode_responses=True)

  info = r.info()
  pprint.pprint(info)

except Exception as err:
  print("Error connecting to Redis: {}".format(err)) 

The above gives me the same error:

Error connecting to Redis: Error while reading from 127.0.0.1:6381 : (1, '[SSL: TLSV13_ALERT_CERTIFICATE_REQUIRED] tlsv13 alert certificate required (_ssl.c:2591)')

However, if I add the missing files, everything will work

import redis
import pprint

try:
   redis_url = "rediss://:[email protected]:6379?ssl_cert_reqs=required&ssl_keyfile=./tls.key&ssl_certfile=./tls.crt&ssl_ca_certs=./ca.crt"
   r = redis.StrictRedis.from_url(redis_url, decode_responses=True)

  info = r.info()
  pprint.pprint(info)

except Exception as err:
  print("Error connecting to Redis: {}".format(err)) 

Proposed Resolution

If I am correct, config.py file needs fixing and also helm chart.

def redis_url(db: int) -> str:
"""Helper to create a Redis URL for a specific database"""
_redis_protocol_prefix = "redis://"
_redis_tls_requirements = ""
if CONFIG.get_bool("redis.tls", False):
_redis_protocol_prefix = "rediss://"
_redis_tls_requirements = f"?ssl_cert_reqs={CONFIG.get('redis.tls_reqs')}"
if _redis_ca := CONFIG.get("redis.tls_ca_cert", None):
_redis_tls_requirements += f"&ssl_ca_certs={_redis_ca}"
_redis_url = (
f"{_redis_protocol_prefix}"
f"{quote_plus(CONFIG.get('redis.username'))}:"
f"{quote_plus(CONFIG.get('redis.password'))}@"
f"{quote_plus(CONFIG.get('redis.host'))}:"
f"{CONFIG.get_int('redis.port')}"
f"/{db}{_redis_tls_requirements}"
)
return _redis_url

If you approve, I can try to work on this over the weekend.

Tasks

Preview Give feedback

Workaround

The simplest workaround I could think of is to add required TLS files into query string. Since AUTHENTIK_REDIS__TLS_CA_CERT variable is only used for concatenation of the Redis url, simply add ssl_keyfile ssl_certfile after the ca_certs file, and point them to the mounted secrets.

- name: AUTHENTIK_REDIS__TLS_CA_CERT
  value: "/secrets/redis-tls/ca.crt&ssl_keyfile=/secrets/redis-tls/tls.key&ssl_certfile=/secrets/redis-tls/tls.crt"

This is an example for helm chart to deploy Authentik to Kubernetes. Update your values.yaml accordingly(this is not a valid nor full config)

global:
  env:
    # Redis config
    - name: AUTHENTIK_REDIS__HOST
      value: "redis.authentik.svc.cluster.local"
    - name: AUTHENTIK_REDIS__PASSWORD
      valueFrom:
        secretKeyRef:
          name: redis-password
          key: redis-password
    - name: AUTHENTIK_REDIS__TLS
      value: "True"
    - name: AUTHENTIK_REDIS__TLS_REQS
      value: "required"
    - name: AUTHENTIK_REDIS__TLS_CA_CERT
      value: "/secrets/redis-tls/ca.crt&ssl_keyfile=/secrets/redis-tls/tls.key&ssl_certfile=/secrets/redis-tls/tls.crt"

  # Mount tls secrets to /secrets
  volumes:
    - name: redis-tls
      secret:
        secretName: redis-tls
        defaultMode: 0644
        items:
          - key: tls.key
            path: tls.key
          - key: tls.crt
            path: tls.crt
          - key: ca.crt
            path: ca.crt

  volumeMounts:
    - name: redis-tls
      mountPath: "/secrets/redis-tls"
      readOnly: true
  
  # Update securityContext so pod can access the mounted secrets
  securityContext:
    runAsUser: 1000     # UID of authentik user
    runAsGroup: 1000    # GID of authentik user
    fsGroup: 1000

Using this approach, I was able to deploy Authentik.

@mike-pisman mike-pisman added the bug Something isn't working label Nov 15, 2024
@mike-pisman
Copy link
Author

A little update:

First of all, I forgot to mention that I tried combining 3 certificates into one pem file, but that does not work.

Second, although my workaround works for Authentik server itself, it does not work for parts of authentik written in GO like outposts for example. Authentik server uses python to connect to Redis, outposts, on the other hand, are written in GO Lang, which complicates things even worse. While Authentik server simply append the contents of the TLS Config to connection URL, outposts actually load the file from the path specified in the config, which causes an error that file "/secrets/redis-tls/ca.crt&ssl_keyfile=/secrets/redis-tls/tls.key&ssl_certfile=/secrets/redis-tls/tls.crt" does not exist for obvious reasons.

ca := config.Get().Redis.TLSCaCert
if ca != nil {
// Get the SystemCertPool, continue with an empty pool on error
rootCAs, _ := x509.SystemCertPool()
if rootCAs == nil {
rootCAs = x509.NewCertPool()
}
certs, err := os.ReadFile(*ca)
if err != nil {
a.log.WithError(err).Fatalf("Failed to append %s to RootCAs", *ca)
}
// Append our cert to the system pool
if ok := rootCAs.AppendCertsFromPEM(certs); !ok {
a.log.Println("No certs appended, using system certs only")
}
tls.RootCAs = rootCAs

@authentik-automation
Copy link
Contributor

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@authentik-automation authentik-automation bot added the status/stale This issue has not been updated recently label Feb 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working status/stale This issue has not been updated recently
Projects
None yet
Development

No branches or pull requests

1 participant