Skip to content

docs: add self-signed certificate guide for OIDC providers#391

Draft
markphelps wants to merge 5 commits intomainfrom
docs/oidc-self-signed-certs
Draft

docs: add self-signed certificate guide for OIDC providers#391
markphelps wants to merge 5 commits intomainfrom
docs/oidc-self-signed-certs

Conversation

@markphelps
Copy link
Contributor

@markphelps markphelps commented Feb 23, 2026

Adds documentation for trusting self-signed/internal CA certificates when using OIDC with self-hosted identity providers (Keycloak, Dex, etc).

Context: flipt-io/flipt#5296 — Users with self-hosted OIDC providers using internal CAs get x509: certificate signed by unknown authority errors. A community member (kristofersokk) shared the workaround; this PR documents it properly.

Includes:

  • Dockerfile example with update-ca-certificates
  • Kubernetes deployment example (init container + shared volume)
  • Verification command with openssl s_client

Closes flipt-io/flipt#5296

Add documentation for trusting self-signed/internal CA certificates
when using OIDC with self-hosted identity providers (Keycloak, Dex, etc).

Includes:
- Dockerfile example with update-ca-certificates
- Kubernetes deployment example (init container + shared volume)
- Verification command

Closes flipt-io/flipt#5296
@claude
Copy link
Contributor

claude bot commented Feb 23, 2026

PR Review

This is a useful addition that addresses a real pain point for users with self-hosted OIDC providers. The overall structure is clear and the context is well-explained. A few issues worth addressing before merging:


Must Fix

1. Missing language tag on error code block

CLAUDE.md requires language tags on all code blocks. The error message block at the top of the section has no language tag:

```
tls: failed to verify certificate: x509: certificate signed by unknown authority
```

Should be at minimum ```text``` or ``````` with a text tag.


2. Kubernetes init container may not have update-ca-certificates available

The init container uses flipt/flipt:latest as its image and calls update-ca-certificates, but the stock Flipt image likely doesn't have the ca-certificates package pre-installed (the Docker example explicitly adds it with apk add, but the Kubernetes example skips this step).

Consider either:

  • Using a small purpose-built image (e.g. alpine:latest) that has apk available, or
  • Adding a step to install the package in the init container's args:
    args:
      - |
        apk add --no-cache ca-certificates &&
        cp /certs/*.crt /usr/local/share/ca-certificates/ &&
        update-ca-certificates &&
        cp -r /etc/ssl/certs/* /shared-certs/

3. Kubernetes Deployment YAML is missing required fields

The example is missing replicas, selector, and template.metadata.labels, which are required for a valid Deployment. Without the selector, the YAML won't apply. This will confuse users trying to copy-paste it. At minimum, add:

spec:
  replicas: 1
  selector:
    matchLabels:
      app: flipt
  template:
    metadata:
      labels:
        app: flipt
    spec:
      ...

Should Fix

4. Use proper subheadings instead of bold text for examples

**Dockerfile example:** and **Kubernetes example (mount CA cert as a Secret):** are formatted as bold text, but the rest of the file uses #### or ##### headings for subsections of this level. Proper headings appear in the "On this page" navigation and are more consistent with the surrounding content.


5. Error message prefix may vary

The documented error:

tls: failed to verify certificate: x509: certificate signed by unknown authority

The prefix tls: failed to verify certificate: is context-dependent — it may not appear in all log formats. The core error is x509: certificate signed by unknown authority. Worth noting both forms, or just the canonical Go error, so users searching logs can find this section.


Nice to Have

6. Cross-reference to ca_path for the Kubernetes auth method

Lines 588–590 in the same file document a ca_path field for the kubernetes auth method as an alternative approach to the certificate trust problem. Adding a brief note that OIDC auth does not expose ca_path (and therefore requires the trust store approach) would help users understand why these docs differ.


Overall this is good documentation that fills a real gap. The Kubernetes YAML completeness issue is the most important to fix before this goes out — incomplete examples can frustrate users more than no example at all.

@claude
Copy link
Contributor

claude bot commented Feb 27, 2026

PR Review

Good addition to the docs — this fills a real gap for users with self-hosted OIDC providers. The content is clear and the use cases are well-chosen. A few issues to address before merging:


Blocking: Malformed code block inside the <Tip> component

The <Tip> component has a triple-backtick code block embedded inline inside JSX text. This won't render as a proper code block in Mintlify — it will likely appear as raw backtick characters in a single broken line.

The code block must be on its own lines within the JSX component:

<Tip>
  You can verify that the certificates are trusted by running:

  ```bash
  echo | openssl s_client -brief -connect your-oidc-provider:443 -verify_hostname your-oidc-provider 2>&1 | grep Verification

You should see Verification: OK if the CA is properly trusted.


---

### Blocking: Kubernetes `Deployment` is missing required fields

The YAML example is missing the required `selector` field (and conventionally `replicas`). Without `selector`, `kubectl apply` will return a validation error. Add these under `spec`:

```yaml
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flipt
  template:
    metadata:
      labels:
        app: flipt
    spec:
      # ... rest of spec

Suggestion: Add a kubectl create secret snippet

Users will need to create the internal-ca-certs Secret before the Deployment will work. A small note showing how to create it would make the Kubernetes example self-contained:

kubectl create secret generic internal-ca-certs \
  --from-file=ca.crt=/path/to/your/ca.crt

Minor: openssl s_client -brief portability

The -brief flag is available in OpenSSL >= 1.1.0 but absent in LibreSSL (macOS default) and some older Linux distributions. The command works fine in most container environments, but worth noting or offering | tail -1 as a portable alternative.


What looks good

  • The error message (x509: certificate signed by unknown authority) is exact and easy to grep for — great for discoverability.
  • Alpine-specific paths (apk, /usr/local/share/ca-certificates/) are consistent with what Flipt uses.
  • The init container + shared volume pattern is the idiomatic Kubernetes approach.
  • Section placement (after fetch_extra_user_info, before PKCE) is logical.

- Add language tag to error code block
- Use alpine image for init container (has apk available)
- Add apk install step in init container
- Add required K8s Deployment fields (replicas, selector, labels)
- Use proper subheadings instead of bold text
- Note both error message variants for searchability
- Fix malformed code block inside Tip component
- Remove -brief flag from openssl command for portability
- Add kubectl create secret snippet
- Add Note about OIDC lacking ca_path (cross-ref to K8s auth)

Signed-off-by: Mark Phelps <209477+markphelps@users.noreply.github.com>
@markphelps
Copy link
Contributor Author

Addressed all review feedback:

  • Added language tag to error code block
  • Used alpine:latest for init container with apk add step
  • Added required K8s Deployment fields (replicas, selector, labels)
  • Changed bold text to proper ##### subheadings
  • Noted both error message variants for searchability
  • Fixed malformed code block inside <Tip> component
  • Removed -brief flag from openssl command for portability
  • Added kubectl create secret snippet
  • Added <Note> cross-referencing ca_path on the K8s auth method

@claude
Copy link
Contributor

claude bot commented Feb 27, 2026

PR Review

All feedback from the previous review rounds has been addressed — great work. The documentation is now well-structured, accurate, and follows the conventions in CLAUDE.md. A few notes below:


Blocking: CI lint check is failing

The lint job in CI is currently failing (run #22490579960). The cause isn't visible without log access, but it should be investigated and resolved before merging. Common causes in this repo are Vale prose linting warnings (e.g. Microsoft Style Guide flags like need to, weak words, or passive voice) or ESLint MDX issues.

You can reproduce it locally with:

cd docs && npm run lint

And for Vale prose linting:

cd docs && vale v2/configuration/authentication.mdx

What looks good

  • Language tag on error code block (text) ✅
  • Proper ##### subheadings instead of bold text — shows up in "On this page" navigation ✅
  • Both error message variants documented for searchability ✅
  • <Note> cross-referencing the Kubernetes auth ca_path option — helpful context for why this approach differs ✅
  • alpine:latest init container with explicit apk add step ✅
  • All required K8s Deployment fields (replicas, selector, template.metadata.labels) ✅
  • kubectl create secret snippet makes the Kubernetes example self-contained ✅
  • -brief flag removed from openssl for portability ✅
  • <Tip> code block is properly formatted with blank lines inside the JSX component ✅

Once the lint failure is resolved, this looks ready to merge.

Signed-off-by: Mark Phelps <209477+markphelps@users.noreply.github.com>
@claude
Copy link
Contributor

claude bot commented Feb 27, 2026

PR Review

All feedback from previous review rounds has been addressed. The content is well-structured and follows the conventions in CLAUDE.md. A few minor observations below:


CI checks are still running

The lint and claude-review checks are in progress. Worth confirming they pass before merging — previous lint failures in this PR suggest Vale or ESLint may flag something. You can reproduce locally with:

cd docs && npm run lint
cd docs && vale v2/configuration/authentication.mdx

Minor: <Tip> content indentation inconsistency

The <Note> component content is indented 2 spaces, but the <Tip> content is not indented:

<Note>
  Unlike the [`kubernetes` auth method](...), ...   ← indented
</Note>

<Tip>
You can verify ...   ← not indented

This is purely cosmetic and won't affect rendering, but aligning the style is a nice touch for consistency.


Minor: latest image tag in Dockerfile example

The Dockerfile uses FROM flipt/flipt:latest. A brief inline comment like # replace with a specific version tag in production would be a helpful nudge for users copy-pasting the example into real workloads. The Kubernetes example has the same pattern with flipt/flipt:latest and alpine:latest.


What looks good

  • Language tag on error code block (text) ✅
  • Both error message variants documented for searchability ✅
  • <Note> cross-referencing ca_path on the Kubernetes auth method ✅
  • ##### subheadings instead of bold text ✅
  • alpine:latest init container with explicit apk add ca-certificates step ✅
  • All required Kubernetes Deployment fields (replicas, selector, template.metadata.labels) ✅
  • kubectl create secret snippet makes the Kubernetes example self-contained ✅
  • -brief flag removed from openssl command for portability ✅
  • <Tip> code block properly formatted with blank lines inside JSX ✅
  • Shared certs volume mounted readOnly: true in the Flipt container ✅

Overall this is solid documentation that fills a real gap. The two minor points above are purely optional polish — pending a clean CI run, this looks ready to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat : allow trusting self-signed certificates for OIDC

1 participant