Skip to content

Migrate LDAP integration from legacy to IPA#973

Open
mprpic wants to merge 1 commit intomainfrom
ipa-ldap
Open

Migrate LDAP integration from legacy to IPA#973
mprpic wants to merge 1 commit intomainfrom
ipa-ldap

Conversation

@mprpic
Copy link
Copy Markdown
Contributor

@mprpic mprpic commented Mar 19, 2026

Migrate from ldap.corp.redhat.com (anonymous binds, deprecated) to ipa.corp.redhat.com (authenticated binds via service account).

Go client:

  • Replace skipTLSVerify with bindDN, bindPassword, caCertPath params
  • connect() loads custom CA cert (appended to system pool) and performs authenticated Bind()
  • Default groupBaseDN derivation updated from ou=managedGroups to cn=groups (IPA pattern)
  • Deduplicate group memberships

Manifests:

  • Update ldap-config.yaml (all overlays) with IPA URL and base DNs, add LDAP_BIND_DN, remove LDAP_SKIP_TLS_VERIFY
  • Add ldap-credentials.yaml Secret (all overlays) for LDAP_BIND_PASSWORD
  • Add LDAP_CA_CERT_PATH env var and ldap-ca-cert volume mount to backend deployment (optional, for TLS verification)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 01984148-4483-4481-9f26-405b00061727

📥 Commits

Reviewing files that changed from the base of the PR and between 0954ca5 and f9fc123.

📒 Files selected for processing (12)
  • components/backend/ldap/client.go
  • components/backend/ldap/client_test.go
  • components/backend/main.go
  • components/manifests/base/core/backend-deployment.yaml
  • components/manifests/overlays/kind/kustomization.yaml
  • components/manifests/overlays/kind/ldap-config.yaml
  • components/manifests/overlays/kind/ldap-credentials.yaml
  • components/manifests/overlays/local-dev/kustomization.yaml
  • components/manifests/overlays/local-dev/ldap-config.yaml
  • components/manifests/overlays/local-dev/ldap-credentials.yaml
  • components/manifests/overlays/production/ldap-config.yaml
  • components/manifests/overlays/production/ldap-credentials.yaml

Walkthrough

Refactors LDAP client to add DNS SRV discovery, authenticated bind support, and configurable CA certificate loading/enforcement (TLS ≥1.2). Removes TLS skip-verify, changes group base DN derivation and group deduplication, and updates runtime init and Kubernetes manifests to supply bind and CA configuration.

Changes

Cohort / File(s) Summary
LDAP Client Core
components/backend/ldap/client.go
Reworked NewClient signature to NewClient(url, srvDomain, baseDN, groupBaseDN, bindDN, bindPassword, caCertPath string) (*Client, error). Added dial() with DNS SRV _ldap._tcp.<srvDomain> discovery and LDAPS attempts, TLS enforcement (MinVersion TLS1.2) with optional CA PEM loading, and conditional Bind when bindDN provided. Updated group base DN derivation and deduplicate user groups.
LDAP Client Tests
components/backend/ldap/client_test.go
Updated tests to the new NewClient(...)(*Client, error) signature; immediate error checks added and assertions updated for new DN shapes and bindDN.
Backend Initialization
components/backend/main.go
LDAP init triggers when LDAP_URL OR LDAP_SRV_DOMAIN set. Reads LDAP_BIND_DN, LDAP_BIND_PASSWORD, LDAP_CA_CERT_PATH; removed LDAP_SKIP_TLS_VERIFY. Client creation errors leave LDAP disabled and are logged. Default LDAP_BASE_DN updated to IPA-style DN.
Kubernetes Deployment Config
components/manifests/base/core/backend-deployment.yaml
Replaced LDAP_SKIP_TLS_VERIFY usage with LDAP_BIND_DN; added envs LDAP_SRV_DOMAIN, LDAP_BIND_PASSWORD, LDAP_CA_CERT_PATH. Added optional ldap-ca-cert ConfigMap volume and mount at /etc/pki/custom-ca.
Kustomize Overlays
components/manifests/overlays/*/kustomization.yaml
Added ldap-config.yaml and ldap-credentials.yaml to overlay resources (kind/local-dev overlays updated).
LDAP ConfigMaps (overlays)
components/manifests/overlays/*/ldap-config.yaml
Added/updated ConfigMaps to include LDAP_SRV_DOMAIN, LDAP_GROUP_BASE_DN, LDAP_BIND_DN, LDAP_CA_CERT_PATH; updated LDAP_URL and LDAP_BASE_DN to IPA-style values and removed LDAP_SKIP_TLS_VERIFY.
LDAP Credentials Secrets (overlays)
components/manifests/overlays/*/ldap-credentials.yaml
Added ldap-credentials Secret manifests (Opaque) with LDAP_BIND_PASSWORD placeholder for each overlay.

Sequence Diagram(s)

sequenceDiagram
    participant App as Backend App
    participant DNS as DNS Resolver
    participant LDAP as LDAP Server

    App->>App: NewClient(url, srvDomain, baseDN, groupBaseDN, bindDN, bindPassword, caCertPath)
    alt srvDomain provided
        App->>DNS: SRV lookup "_ldap._tcp.<srvDomain>"
        DNS-->>App: list of SRV targets
        loop try each SRV target
            App->>LDAP: Dial ldaps://target:636 (TLS using caCertPath, TLS1.2+)
            alt dial success
                LDAP-->>App: TCP+TLS established
                alt bindDN provided
                    App->>LDAP: Bind(bindDN, bindPassword)
                    LDAP-->>App: Bind success / error
                end
                App-->>App: return connected client or bind error
            else dial failed
                LDAP--xApp: dial error
            end
        end
    else no SRV or SRV failed
        App->>LDAP: Dial configured URL (ldaps://...)
        LDAP-->>App: TCP+TLS established or error
        alt bindDN provided
            App->>LDAP: Bind(bindDN, bindPassword)
            LDAP-->>App: Bind result
        end
        App-->>App: return client or error
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: migrating LDAP integration from legacy authentication to IPA with authenticated binds.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering Go client refactoring, manifest updates, and configuration changes for the IPA migration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ipa-ldap
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can enable review details to help with troubleshooting, context usage and more.

Enable the reviews.review_details setting to include review details such as the model used, the time taken for each step and more in the review comments.

@mprpic
Copy link
Copy Markdown
Contributor Author

mprpic commented Mar 19, 2026

@ktdreyer @Gkrumbach07 When this gets deployed for the first time, someone needs to manually upload the cert and LDAP creds into the relevant ConfigMap/Secret. Does that get done manually, or do we have any deployment scripts/playbooks I need to modify somewhere?

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/backend/ldap/client.go`:
- Around line 86-97: The code reads a CA file into caCertPath and calls
rootCAs.AppendCertsFromPEM(...) but doesn't check the boolean result; if the PEM
contains no valid certs the TLS trust root will be incomplete. Change the block
that sets tlsConfig.RootCAs to validate AppendCertsFromPEM returned true and
return an error if it returned false (include caCertPath in the error), ensuring
this check occurs after os.ReadFile and before assigning tlsConfig.RootCAs;
reference the caCertPath, rootCAs, AppendCertsFromPEM, and tlsConfig.RootCAs
symbols when making the change.

In `@components/backend/main.go`:
- Around line 138-153: The LDAP setup currently fatals on any NewClient error
and logs "initialized" before a real bind; change ldap.NewClient error handling
to treat failures as non-fatal (set handlers.LDAPClient = nil and log a warning)
unless an explicit required flag is set, and after creating ldapClient call its
real connectivity/auth method (e.g., ldapClient.Bind or ldapClient.Ping —
whichever exists) and only assign handlers.LDAPClient and log "LDAP client
initialized" after that succeeds; if the bind/check fails, disable the LDAP
client, log the detailed error, and continue startup instead of calling
log.Fatalf. Ensure you reference ldap.NewClient, handlers.LDAPClient and the
client Bind/Ping method in the fix.

In `@components/manifests/base/core/backend-deployment.yaml`:
- Around line 297-300: The ldap-ca-cert ConfigMap volume in the Deployment's Pod
spec is not marked optional, which will cause pods to fail when LDAP isn't
configured; update the volume definition for the volume named "ldap-ca-cert"
(the entry under volumes where configMap: name: ldap-ca-cert) to include
optional: true so the mount is skipped when the ConfigMap is absent.

In `@components/manifests/overlays/production/ldap-credentials.yaml`:
- Around line 1-9: The production overlay currently commits a tracked Secret
named "ldap-credentials" containing a placeholder LDAP_BIND_PASSWORD; remove the
hardcoded stringData entry and stop versioning the secret. Instead, remove
LDAP_BIND_PASSWORD from this manifest (or delete the Secret resource entirely)
and wire the deployment to obtain the real password from your secret manager/CI
secret-injection mechanism (e.g., ExternalSecrets/SecretProviderClass/CI vault
injection) so the actual value is never stored in git; update any references to
the Secret name "ldap-credentials" in manifests to match the injected/managed
secret name or document the injection step in your deployment pipeline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9318714-a999-4331-91a6-7ea2f97082be

📥 Commits

Reviewing files that changed from the base of the PR and between f8ac621 and 583694c.

📒 Files selected for processing (12)
  • components/backend/ldap/client.go
  • components/backend/ldap/client_test.go
  • components/backend/main.go
  • components/manifests/base/core/backend-deployment.yaml
  • components/manifests/overlays/kind/kustomization.yaml
  • components/manifests/overlays/kind/ldap-config.yaml
  • components/manifests/overlays/kind/ldap-credentials.yaml
  • components/manifests/overlays/local-dev/kustomization.yaml
  • components/manifests/overlays/local-dev/ldap-config.yaml
  • components/manifests/overlays/local-dev/ldap-credentials.yaml
  • components/manifests/overlays/production/ldap-config.yaml
  • components/manifests/overlays/production/ldap-credentials.yaml

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
components/manifests/overlays/production/ldap-credentials.yaml (1)

1-9: ⚠️ Potential issue | 🟠 Major

Don't ship a production bind-password placeholder.

Applying this overlay still creates ldap-credentials with a bogus value, so production LDAP is either broken until the cluster is patched manually or the real password gets committed here. Provision this Secret via your secret manager / deployment automation instead of a versioned manifest.

As per coding guidelines, focus on major issues impacting performance, readability, maintainability and security.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/manifests/overlays/production/ldap-credentials.yaml` around lines
1 - 9, The manifest currently commits a production Secret named
"ldap-credentials" with a real-looking LDAP_BIND_PASSWORD value; remove the
hardcoded LDAP_BIND_PASSWORD entry from the overlay and stop checking this
Secret into version control — instead wire the deployment to fetch the secret at
deploy-time via your secret manager or tooling (e.g.,
ExternalSecret/SealedSecret, k8s secretGenerator excluded from git, or your
CI/CD vault integration) and update any references in deployment manifests to
use that external secret name; ensure no plaintext password remains in the
"ldap-credentials" resource or repo and add documentation/comments in the
overlay explaining that the Secret is provided by the secret manager at deploy
time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/manifests/overlays/kind/ldap-config.yaml`:
- Around line 8-12: The LDAP_CA_CERT_PATH variable in the overlay should not
point at a CA file that this overlay doesn't provision; either remove/unset
LDAP_CA_CERT_PATH from the manifest (so startup won't attempt to load a
non-existent file) or add provisioning for the CA material (create a
Secret/ConfigMap containing the CA and update the overlay to mount it at
/etc/pki/custom-ca/rh-it-root-ca.pem and reference that mount); update the
manifest entry LDAP_CA_CERT_PATH accordingly and ensure the
deployment/volume/mount that supplies the file is present so LDAP client
initialization can reliably find the file.

In `@components/manifests/overlays/local-dev/ldap-config.yaml`:
- Around line 8-13: The LDAP_CA_CERT_PATH environment variable in the LDAP
config overlay (LDAP_CA_CERT_PATH in
manifests/overlays/local-dev/ldap-config.yaml) points to a CA file that this
overlay does not provision; remove or leave LDAP_CA_CERT_PATH unset in this
overlay (or change to an explicitly optional/empty value) so startup does not
try to load a non-existent CA file, or alternatively add provisioning of the CA
artifact to the same overlay/deployment so the referenced path is guaranteed to
exist before the app reads it.

---

Duplicate comments:
In `@components/manifests/overlays/production/ldap-credentials.yaml`:
- Around line 1-9: The manifest currently commits a production Secret named
"ldap-credentials" with a real-looking LDAP_BIND_PASSWORD value; remove the
hardcoded LDAP_BIND_PASSWORD entry from the overlay and stop checking this
Secret into version control — instead wire the deployment to fetch the secret at
deploy-time via your secret manager or tooling (e.g.,
ExternalSecret/SealedSecret, k8s secretGenerator excluded from git, or your
CI/CD vault integration) and update any references in deployment manifests to
use that external secret name; ensure no plaintext password remains in the
"ldap-credentials" resource or repo and add documentation/comments in the
overlay explaining that the Secret is provided by the secret manager at deploy
time.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fcbd04e0-082b-47ea-87e8-1eca374fa85a

📥 Commits

Reviewing files that changed from the base of the PR and between 583694c and 0954ca5.

📒 Files selected for processing (12)
  • components/backend/ldap/client.go
  • components/backend/ldap/client_test.go
  • components/backend/main.go
  • components/manifests/base/core/backend-deployment.yaml
  • components/manifests/overlays/kind/kustomization.yaml
  • components/manifests/overlays/kind/ldap-config.yaml
  • components/manifests/overlays/kind/ldap-credentials.yaml
  • components/manifests/overlays/local-dev/kustomization.yaml
  • components/manifests/overlays/local-dev/ldap-config.yaml
  • components/manifests/overlays/local-dev/ldap-credentials.yaml
  • components/manifests/overlays/production/ldap-config.yaml
  • components/manifests/overlays/production/ldap-credentials.yaml

@ktdreyer
Copy link
Copy Markdown
Contributor

Does that get done manually, or do we have any deployment scripts/playbooks I need to modify somewhere?

Manually today until we have vault (https://redhat.atlassian.net/browse/RHOAIENG-47031)

In the meantime you can store the secrets in the team Bitwarden collection

Migrate from ldap.corp.redhat.com (anonymous binds, deprecated) to
ipa.corp.redhat.com (authenticated binds via service account).

Go client:
- Replace skipTLSVerify with bindDN, bindPassword, caCertPath params
- connect() loads custom CA cert (appended to system pool) and performs
  authenticated Bind()
- Default groupBaseDN derivation updated from ou=managedGroups to
  cn=groups (IPA pattern)
- Deduplicate group memberships

Manifests:
- Update ldap-config.yaml (all overlays) with IPA URL and base DNs,
  add LDAP_BIND_DN, remove LDAP_SKIP_TLS_VERIFY
- Add ldap-credentials.yaml Secret (all overlays) for LDAP_BIND_PASSWORD
- Add LDAP_CA_CERT_PATH env var and ldap-ca-cert volume mount to
  backend deployment (optional, for TLS verification)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Prpič <mprpic@redhat.com>
@ambient-code
Copy link
Copy Markdown
Contributor

ambient-code bot commented Mar 27, 2026

Review Queue Status

Check Status Detail
CI pass ---
Conflicts pass ---
Reviews FAIL CodeRabbit Major: LDAP_CA_CERT_PATH set but file not provisioned; versioned password placeholder

Action needed: Address CodeRabbit Major issues on CA cert path and credentials management

Auto-generated by Review Queue workflow. Updated when PR changes.

@ambient-code ambient-code bot added this to the Review Queue milestone Mar 30, 2026
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.

2 participants