Skip to content

Implementation of basic controller logic - #21

Merged
Kirill Ilin (sircthulhu) merged 5 commits into
mainfrom
13-impl-basic-controller-logic
Mar 15, 2024
Merged

Kirill Ilin (sircthulhu) merged 5 commits into
mainfrom
13-impl-basic-controller-logic

Conversation

@sircthulhu

@sircthulhu Kirill Ilin (sircthulhu) commented Mar 14, 2024 •

Copy link
Copy Markdown
Collaborator

Controller now can successfully bootstrap etcd cluster :)

Controller creates Service, ConfigMap and StatefulSet based on EtcdCluster CR
Only EmptyDir storage is supported
Initialized status is being set and updated

fixes #13

- sts, svc and cm are created by operator
- "Initialized" status is being set and updated
- etcd cluster successfully bootstraps
Comment thread config/manager/manager.yaml Outdated
Comment on lines +73 to +74
image: controller:latest
imagePullPolicy: Never

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggest use full image path ghcr.io/aenix-io/controller:latest and imagePullPolicy: IfNotPresent for reuse yaml in static manifests and helm.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It should be ghcr.io/aenix-io/etcd-operator/controller:latest or ghcr.io/aenix-io/etcd-operator:latest

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Or ghcr.io/aenix-io/etcd-operator/etcd-operator:latest

Oleg Kunitsyn (@hiddenmarten) could you comment on this, please?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Andrei Kvapil (@kvaps)
Sure, I think it's better to use a simple structure of image tag, that will correspond with a GitHub repo path (It helps to avoid confusion):
{registry}/{organisation}/{application}:{versionBySemVer}

So, as a result:
ghcr.io/aenix-io/etcd-operator:v0.0.0

@sircthulhu
Kirill Ilin (sircthulhu) enabled auto-merge (squash) March 15, 2024 06:07
Comment thread api/v1alpha1/etcdcluster_types.go Resolved
@sircthulhu
Kirill Ilin (sircthulhu) deleted the 13-impl-basic-controller-logic branch March 15, 2024 09:25
Terry Tang (saymololy) pushed a commit to saymololy/etcd-operator that referenced this pull request Nov 2, 2026
…ck#21)

* feat: TLS support via BYO Secret refs (client + peer planes)

Adds spec.tls with independently optional .client and .peer subtrees that
reference user-provided Secrets. Within the client plane, presence of
operatorClientSecretRef is the implicit mTLS toggle; peer is always mTLS.
The whole subtree is CEL-locked immutable post-create — toggling TLS in
place is a rolling restart that has to land on the operator's etcd client
and every member Pod in lockstep, which v1 doesn't perform.

The cluster controller mirrors the propagated secret refs onto each
EtcdMember at creation so the member controller is self-sufficient.
EtcdClientFactory now takes a *tls.Config and the operator builds one from
the cluster's serverSecretRef.ca.crt (verify-server) and, in mTLS mode,
operatorClientSecretRef.tls.{crt,key} (client identity). buildPod mounts
the referenced Secrets, wires the etcd --cert-file/--key-file/--trusted-
ca-file/--client-cert-auth/--peer-* flags, and switches the kubelet
readiness probe to /health on a plaintext :2381 metrics listener (kubelet
HTTPGet probes dial the Pod IP and can't present a client cert).

Two operator-visible constraints land in the docs because etcd enforces
them implicitly:

  - The server cert MUST carry clientAuth in its EKU alongside serverAuth.
    The grpc-gateway loopback self-dials the client API presenting the
    server cert as a client cert, and Go's crypto/tls enforces
    ExtKeyUsageClientAuth server-side during verification. Same reason
    the server-issuing CA must be present in --trusted-ca-file (the
    seeded ca.crt of serverSecretRef doubles as the trust bundle).

  - The peer cert MUST cover *.<cluster>.<ns>.svc.<cluster-domain> as a
    DNS SAN, not only the shortname wildcard. etcd's peer-mTLS verifier
    reverse-DNS-looks-up the connecting peer's IP and matches the
    resulting fully-qualified hostname against the cert's SANs; without
    the FQDN wildcard the seed silently EOFs every incoming peer
    connection and joining members crashloop on discovery failed.

Tests: buildPod permutations (plaintext / server-TLS-only / mTLS / peer-
TLS), deriveMemberTLS cluster→member projection, ensurePod precheck for
missing Secret, plus CEL envtest cases covering both add-from-nil and
remove-to-nil rejection and subtree-immutability. Existing tests updated
for the new helper signatures.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Signed-off-by: Timofei Larkin <[email protected]>

* fixup: surface TLS-config errors + correct rotation doc + cp typo

Three small follow-ups:

  - The promote-after-converged branch swallowed both buildOperatorTLSConfig
    and EtcdClientFactory errors silently. Log them and fall through to
    updateStatus (matching the comment's intent and scaleUp's behaviour).
    A missing/typo'd operator-client Secret was previously a steady stream
    of silent 10s requeues with no operator log line.

  - The Phase 1 rotation procedure said "etcd reads the cert files at
    startup and won't pick up the change". That's wrong: Go's crypto/tls
    re-reads --cert-file / --key-file per handshake via GetCertificate,
    so server and peer certs hot-swap without a Pod restart. What does
    need a restart is the trust bundle (--trusted-ca-file /
    --peer-trusted-ca-file), which gets baked into an x509.CertPool at
    config time. Operator-side material rotates on the next reconcile
    because buildOperatorTLSConfig rebuilds the *tls.Config each time.
    Replaced the two-step blanket procedure with a per-material table.

  - operations.md's kubectl cp recipe used `<ns>/<some-client-cert-dir>`
    as the source path, which isn't valid kubectl cp syntax. Rewrote to
    a concrete local-directory source.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Signed-off-by: Timofei Larkin <[email protected]>

---------

Signed-off-by: Timofei Larkin <[email protected]>
Co-authored-by: Claude Opus 4.7 <[email protected]>
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.

Write basic etcd-operator logic

6 participants