The note explaining why this chart spells the field `tls.issuer` called
the other charts' switch `tls.issuer` as well, which inverted it: it read
as though those charts use this same key to mean on/off. They spell it
`tls.enabled`.
Restore that name and hedge the claim to "some other charts". The key is
not uniformly a switch elsewhere either — one chart uses it to select
whether a hostname is added to a certificate its engine serves regardless
— so an unqualified "other charts" overstates how settled the meaning is.
Link the epic tracking the convergence of the TLS surface, so the
divergence the note describes points somewhere instead of only being
asserted.
Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The include selector matches by label and carries no name constraint, so
any Secret of this instance that acquires the tenant-ca label is promoted
to the tenant with its data copied verbatim. The label on the source is
policy-guarded; the one on the destination is not. Exclude is evaluated
first and short-circuits, so naming the dangerous Secrets closes the part
of that gap we can enumerate.
Listed by group with the reason each is dangerous: the private keys from
both issuers, the internal database credentials, the backup S3 keys and
restic password, and the registry pull secret.
The guarantee is only as wide as the list. Matching is by exact name with
no globs, so a Secret added by a future operator version, or one created
transiently during a rotation, is not covered — the protection that holds
in general is still that only the extraction controller writes the label.
mariadb-operator has no rotation-snapshot Secret of the kind that makes
this worse elsewhere; its Secret names are fixed.
The existing guard against a key-bearing name is rescoped to
secrets.include while here, since such a name under exclude is the
backstop working rather than a leak.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
tls.enabled read as a switch and was not one — TLS is served under every
value, and what the field actually chose was which authority issues the
server certificate. The same key means on/off in other charts here, so a
tenant carrying that habit across would have read this exactly backwards.
Replace it with tls.issuer: operator | cert-manager, defaulting to
operator. The value now states the behaviour instead of needing prose to
undo the name: operator is what runs today, so the fact that nothing
changes on upgrade is visible in the default rather than argued in a
comment. Being an enum, a typo is rejected by the schema, which a bool
could not do.
The explanation the old name required is gone with it — the helper
docblock and the CR comment lose the paragraphs that existed only to say
this was not a switch, and the README states the split in a table.
Not marked breaking: the field is introduced by this series and does not
exist on the target branch, so there is no released spelling to migrate
from. Breaking is measured against what is merged, not against the
intermediate history of the branch.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Four claims of mine were broader than the thing they described.
The bats header said it pins the invariants deciding whether a private
key can reach a tenant. Three of its tests touch the declaration that the
API does not accept yet, so they pin an intended spelling and nothing
more; if the field lands under another name they stay green while the
feature does nothing. Say which tests are live and which are placeholders.
The certificate comment said the operator skips reconciliation entirely.
It skips issuance, which is why SANs go unvalidated, but it still reads
the Secret for the pod annotation hash and status.
The README mapped the client's verification default onto the version
enum, which selects the server image. The default belongs to the client
library, so an 11.4 client verifies against a 10.6 server.
The backup guard is described as catching a missing or unusable bundle.
On a fresh managed-TLS install the bundle can be present and non-empty
while holding only the operator's client CA, and the failure lands at
verification instead. Note the window, and note in the README that a new
instance stays down until cert-manager issues.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
These strings flow into the ApplicationDefinition schema and become the
help text beside the fields in the console. They had grown into
paragraphs of rationale — 704 and 613 characters against 48 for the
neighbouring external — which is the wrong length for a form label and
duplicated what the README already explains at the right length.
Say what the field does and that it is opt-in; the reasoning stays in the
README, which is where a reader goes for it.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Two claims of mine were wrong about mechanism.
The empty-selector warning said such a selector would project every Secret
in the namespace. The lineage webhook computes those labels only for
objects whose ownership resolves to the application, so the reach is the
instance's own Secrets. Still the thing to prevent — that set contains
-ca-tls and -tls — but the stated reason should match the code, since it
is what a reader checks the guard against.
The teardown step told the user to delete both Secrets with no ordering.
The server keypair stays mounted in the running pods until the operator
reissues from its own CA and rolls the StatefulSet, so following that
literally leaves the next pod unable to start. Wait for the rollout
first.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The note said the hostname check is off on 10.11 and on across 11.x. The
default actually changed in 11.4. Measured all four versions this chart
offers: 10.6 and 10.11 leave it off, 11.4 and 11.8 enable it. Name the
versions rather than the series, since the reader is choosing between
exactly those.
Scope the key-bearing-Secret guard to the secrets block as well. It
scanned the whole file, so a Service whose name ends in -tls would have
tripped it while a Secret entry with a trailing comment slipped past —
the wrong answer in both directions for the check that decides whether a
private key can reach a tenant.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The comment said the operator offers no way to extend its SAN list, as a
standing fact. It is only true of the version pinned here: upstream has
since added serverCertAdditionalNames, which its SAN builder appends. Left
as an absolute, the next operator bump would inherit the workaround
without anyone reconsidering it.
Say which version the limitation belongs to and what to check at the next
bump, since that is the point where handing the leaf back to the operator
becomes possible and most of this template can go.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The kindIs "invalid" guard on required had no coverage, and writing one
showed why: the schema types the field as a boolean and rejects null
before the template runs, so the guard is defensive rather than a live
path. Assert the rejection instead of inventing a rendering that cannot
happen, which also catches the schema being relaxed later.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The text said --ssl-ca alone leaves the hostname unchecked, without
saying for which client. Measured both: the 10.11 client the backup image
ships defaults --ssl-verify-server-cert to off, the 11.x client defaults
it on. The sentence was therefore right for one and wrong for the other,
in the paragraph a reader uses to decide whether their connection is
verified.
Also record why the tenant reaches the anchor through a Role here rather
than through the shared trust-anchor helper: that helper renders the
Secret from a CA supplied as a template value, and this CA only exists at
runtime, so the chart has no PEM to give it.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The comments described the CA-extraction controller in the present tense,
as something that copies the certificate today. It is not in this repo:
the controller, the spec.caCert field it reads, and the tenant-ca label
all arrive with a separate change, and against the current API the block
is pruned on apply. A reader would have gone looking for a controller
that is not there.
State that it is inert until that lands, why it is declared now anyway,
and that the tenant reaches the anchor meanwhile through the plain name
grant beside it, which needs nothing new.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The guard tested only readability, so a present-but-empty ca.crt passed
it and the run continued into exactly the unnamed client error the guard
was added to replace. Empty is reachable rather than theoretical: the
operator omits expired certificates when it assembles the bundle, so a CA
set that has fully expired leaves the file in place with nothing in it.
Check size as well, and say "missing or empty" so the message matches
both cases. Verified by running the rendered script against an absent and
an empty file.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Uninstall removes the cert-manager Secrets now, but turning managed TLS
off while the instance keeps running does not: the post-delete hook does
not run on an upgrade, and cert-manager does not own what it issued. The
note said the Secrets stay behind without saying what to do about it.
Not automating this on upgrade is deliberate. A hook that deletes Secrets
on every reconcile, including for instances that never had TLS, is a
worse thing to get wrong than an inert Secret that no tenant grant
exposes and nothing reads.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The dashboard Role already let the tenant read <release>-ca-bundle, but
the ApplicationDefinition did not list it, so it was never marked as a
tenant resource and never appeared through the API. The documentation
tells clients to fetch exactly that Secret, which worked with kubectl and
not in the interface the platform actually gives tenants.
Name it in secrets.include, the same way kafka names its CA certificates.
This works against the current API, unlike the label selector beside it,
which stays for the projection an unmerged controller will publish — so
the trust anchor is reachable now rather than only after that lands.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
cert-manager is deployed with enableCertificateOwnerRef disabled, so
removing a Certificate leaves the Secret it issued in place. Uninstalling
an instance that used managed TLS therefore left <release>-ca-tls, which
holds the CA signing key, and <release>-tls, which holds the server key,
sitting in a namespace the tenant shares with its other applications, for
as long as the namespace exists.
The chart already had the mechanism: the post-delete hook deletes the
operator-generated password Secrets by name under an RBAC rule scoped to
exactly those names. Add these two to both lists. -ca-bundle stays out —
the operator gives it an ownerRef, so Kubernetes collects it, and naming
it here would widen the grant for nothing.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The client reports an unreadable CA only as "TLS/SSL error: No such file
or directory", with no path and no filename — verified against the
MariaDB client the backup image ships. Since the bundle is an optional
mount, that message is exactly what an operator sees during the window
before the trust bundle is reconciled, and it says nothing about what to
look at. Check the file first and fail with its path and the Secret it
comes from.
Correct the migration note as well. It said nothing changes on upgrade
until TLS is opted into, which is not true for instances still using the
deprecated backup CronJob: their backup client now verifies the server
where before it did not. It verifies against the operator's own bundle
and the operator's certificate already covers the host the job dials, so
no action is needed — but a behaviour change to a running job should be
stated rather than contradicted.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The guard against an empty selector matched only "matchLabels: {}". A
bare "matchLabels:" with nothing nested under it is the same empty
selector — it compiles to match-everything and would project every
Secret in the namespace to the tenant — and it slipped through. Check
that a bare selector is followed by an indented label as well.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The section described one certificate covering the in-cluster names plus
the external hostname, which was true while managed TLS followed
external. It no longer does, so the default for an externally exposed
instance is the operator's certificate — and that one cannot carry the
external hostname, because the operator has no way to learn it.
A reader following the verification instructions on such an instance
would have failed hostname verification with no explanation, having done
everything the page asked. Describe the two issuers separately and say
plainly that verifying an external connection is what tls.enabled: true
is for.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The migration section only walked the enable direction. Reverting hands
issuance back to the operator, which means clients have to pick up its CA
again, and cert-manager leaves the Secrets it issued behind when the
Certificates go away. Neither is dangerous, but both are surprising to
find out afterwards.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The example passed the password on the command line, where it lands in
shell history and in process arguments any other user on the host can
read. Prompting costs nothing in an example whose subject is protecting
the connection.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The bundle volume was a required mount. The operator reconciles it only
after certificates settle, so on first install with managed TLS there is
a window where it does not exist, and a required mount leaves the pod in
ContainerCreating rather than failing. With concurrencyPolicy: Forbid
that one stuck pod blocks every subsequent backup for as long as it
hangs. Marking it optional turns that into a run that fails with a
message naming the missing file, retries, and lets the schedule proceed.
Correct the reason given for enforcement defaulting to false while here.
It said the tenant had nothing to verify the server against, but this
same change grants the tenant read access to the bundle, so the anchor
is reachable. The default is still right — enforcement refuses clients
that have not moved yet, which is a decision to make rather than
something an upgrade does — but that is the reason, and it was stated in
five places, all fed from the values annotations.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The check accepted the label anywhere in the ApplicationDefinition, so a
stray occurrence would satisfy it while the selector that actually
exposes the projection stayed empty or wrong. Scope it to the
matchLabels block it has to appear in.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Making managed TLS opt-in left the suite describing the behaviour it
replaced: the header still mapped external=true with tls.enabled unset
to managed, the section comment and several test titles still said TLS
was enabled via external, and every one of those cases only passed
because it now sets tls.enabled explicitly. The suite is where someone
reads the tri-state contract, so it was the one place still teaching the
old one.
The SAN comment also promised more than the test delivers. Pinning the
list catches an accidental edit to the template, but the expected values
are a copy of what the template renders, so an operator-side rename
would leave it green — and the operator skips certificate reconciliation
entirely when both secret refs are supplied, so it does not check
either. Say that the gap is real and that closing it needs a handshake,
rather than implying it is covered.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
tls.enabled defaulted to the value of external, so every existing
external instance would have moved from the operator's CA to a
chart-issued one on the next platform upgrade, without its owner doing
anything. Clients pinning the operator's ca.crt fail chain validation
the moment the new certificate is served, and external instances are
exactly the population where a copied ca.crt is most likely.
The usual argument for applying something on upgrade does not hold
here: taking over the CA does not raise the security floor. These
instances already serve TLS under the operator's CA, and what changes is
which authority issues it — an architectural move toward the platform
trust contract, not protection against a threat. There is no security
gain to weigh the breakage against, so it becomes a choice.
Rendered for an existing external instance, the result is now identical
to what the operator already applies on its own: TLS on, enforcement
off, no chart-issued certificates. Nothing happens on upgrade.
The default flips as an announced change together with the published
trust anchor, the same way tls.required does.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The check rejecting key-bearing Secrets from the tenant include list
matched only unquoted list entries, while its sibling check was already
quote-agnostic. A quoted entry would have passed both the guard and the
comment claiming it could not.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The TLS section reused the <instance> placeholder that the rest of the
document uses for the MariaDB resource name, but the Secret and the
Service are named after the Helm release, which prefixes it. A reader
following the instructions literally asked for a Secret that does not
exist and connected to a hostname that does not resolve.
Use the prefixed form in that section and say once, at the top, which
name is which.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Two claims were close but not true as written.
The certificate comment said the usage set matches what the operator
issues. The operator also sets the key encipherment bit; this set
deliberately leaves it out, because it covers RSA key transport and is
meaningless for the P-256 key the chart issues. Say that instead of
implying agreement.
The migration note led with enforcement being off, which is true but
buried what actually changes for an existing instance: the CA moves to a
per-instance one. Clients reading the bundle follow it, pinned clients
do not. Instances with external: true take that change on a platform
upgrade rather than an edit of their own, so the opt-out has to be
stated where someone with pinned clients will find it.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The backup client's TLS wiring was gated on the chart managing the
certificates, but enforcement is not. Setting tls.required on an
instance that uses the operator's own CA produced a server refusing
plaintext and a backup job with no CA mounted and no verification
flags, so every run failed — the same failure the MariaDB-dialect fix
addressed, reintroduced through a different gate.
Nothing was gained by the gate. The server serves TLS in every
configuration and the operator reconciles the CA bundle alongside it, so
the client can always verify; connecting unverified was never the
better option.
Two of the tests covering this asserted absence with a partial list
entry, which never matches a whole one, so they passed regardless of
what the template did. They now assert the mount that has to be there.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
tls.required was only emitted when the chart managed the certificates,
so setting it on an instance using the operator's own CA was accepted by
the schema and then dropped on the way to the CR — no enforcement, no
error, no warning. For a setting whose entire purpose is refusing
unprotected connections, silently ignoring it is the worst available
outcome.
The coupling was artificial: in the operator API required sits beside
enabled with no dependency on either certificate reference, and
enforcement works against operator-issued certificates just as well.
Emit it in every configuration and let it mean what it says.
Also loosen the two negative guards in the ApplicationDefinition check,
which required a literal closing quote and exact brace spacing and so
would have missed an unquoted key-bearing source.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Enforcement has to follow the trust anchor, not lead it. The platform
does not yet publish a key-free CA to the tenant, so requiring TLS today
tells clients they must encrypt while giving them nothing to verify the
server against — protection on paper, unverified connections in
practice.
It also cannot be opted out of in time. Enforcement would arrive with a
platform upgrade rather than a user action, and the escape hatch lives
in a field this change is the first to introduce, so an operator has no
way to set it beforehand. The only available order was upgrade, break,
then repair.
Default required to false and let enforcement be chosen. Managed TLS
still issues the per-instance CA and certificate, so the path to
verified connections is in place; what is deferred is refusing the
connections that predate it. The default flips to true as an announced
change once the published anchor is universal, and the field
descriptions say so rather than leaving it implied.
This does not change any running instance: enforcement was never applied
to one. The chart previously sent no enforcement at all unless it managed
the certificates, and managing them is itself opt-in, so an existing
instance keeps the operator's unenforced default either way.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The backup-script guards checked the explicit and the disabled states but
not the inherited one, which is what an external instance actually gets
by default and therefore the state most likely to run a backup against a
server that enforces TLS. Reintroducing the MySQL-only option now fails
three tests instead of two.
The surrounding prose had also fallen behind the behaviour it describes:
the suite header still called the unmanaged rows "TLS disabled" when the
tests below pin TLS as on but unmanaged, one comment still named the leaf
Secret as the trust-anchor source under a test asserting the CA bundle,
another blurred an explicit tls.enabled: null against blanking the whole
tls map, and one case was named for a string input it does not use.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The ApplicationDefinition is where a mistake decides whether a private
key can reach a tenant, and it is the one file in this change the chart
test suite cannot reach: helm-unittest only covers rendered templates,
and the *-rd packages expose no test target.
Add a shell check in the style of the existing kafka one, which the
Makefile discovers automatically. It pins that the CA source is the
operator's key-free bundle rather than either key-bearing Secret, that
the tenant selector is the specific label rather than an empty selector
that would match every Secret in the namespace, and that no key-bearing
Secret is listed by name.
Type required as a pointer while here. As a plain bool it rendered a
default of false in the generated documentation while the description
promised true, and the zero value could not represent an explicit false
for consumers going through the generated struct — which is the value
the documented migration path depends on.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Three corrections to what the rendered objects claim.
The schema defaulted tls.required to true unconditionally, so every CR
carried required: true even where the chart renders no enforcement at
all. The operator reads an absent required as not-enforced, so anyone
reading the CR was told plaintext is refused on an instance that
accepts it. Drop the schema default and let the template supply the
managed default, which keeps enforcement on for managed instances and
silent for the rest.
The tenant grant for the CA bundle was gated on TLS being managed, but
the operator reconciles that bundle whenever TLS is on, which for this
chart is always. Ungate it: the default instance serves TLS, so leaving
the tenant unable to fetch the CA meant it could not verify the server
it was talking to.
Reword the claim that TLS cannot be switched off. The operator does
honour an explicit disable; what is true is narrower, that omitting the
field is not how you select it and this chart always asks for TLS. The
text is what a reader relies on when deciding whether a connection is
protected, so it has to describe the chart rather than invent an
operator invariant.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Two corrections to what the chart tells the platform and the user.
The tls values never controlled whether TLS runs. The operator substitutes
an enabled TLS spec whenever the field is absent, so every instance has
always served TLS, and a chart that omits the block only hides that.
Render it explicitly and let the values select what they actually select:
who owns the CA, and whether TLS is enforced. Rendering the resolved
value instead would be the one change that genuinely turns TLS off on
instances that have it today, which is not something to ship silently.
The field descriptions said the opposite and are corrected with it.
Publication of the trust anchor moves to a declaration on the
ApplicationDefinition, naming the operator's <release>-ca-bundle. That
Secret holds ca.crt alone and carries the previous CA across a rollover,
so the publication path never runs next to a private key at all — better
than labelling the chart's own CA Secret, which does hold one. The labels
on that Secret are dropped rather than left as a second, redundant path.
The tenant keeps direct read access to the bundle so the feature is
usable before the extraction controller exists; that grant is key-free
and comes out once the published anchor is universal.
Also set a commonName on the leaf, which cert-manager otherwise leaves
empty, breaking clients that verify the hostname against the subject
rather than the SAN list.
The CA for external instances changes hands here, from the operator's to
one issued for the instance. A client verifying against
<release>-ca-bundle follows that automatically, because the bundle
carries both CAs; a client that pinned a copied ca.crt has to re-read it.
Enforcement is a separate, opt-in setting and is not changed by this
commit.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The leaf carried client auth alongside server auth. MariaDB treats
server and client certificates as separate roles, and a user declared
REQUIRE X509 accepts any client certificate signed by a trusted CA, so
a server key that also bears client auth can authenticate as that user.
The operator issues its own server certificates with server auth alone
and keeps client auth on the client certificates it manages separately;
match that split.
Drop key encipherment at the same time. It covers RSA key transport and
is inapplicable to the P-256 key this chart issues, where the usage that
matters is digital signature for the ECDHE signature.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Two things the chart got wrong about how mariadb-operator handles TLS.
The operator only reconciles on changes to the Secrets behind
serverCASecretRef and serverCertSecretRef when those Secrets carry its
watch label; the watches are predicate-gated on it. Neither Secret had
the label, and cert-manager owns them rather than the MariaDB resource,
so ownership does not trigger a reconcile either. The leaf rotates its
private key on every renewal, so a renewal would land in the Secret and
the running pods would keep serving the superseded certificate until
the next full resync. Label both Secrets.
The operator also reconciles a trust bundle of its own, named
<release>-ca-bundle, whenever TLS is enabled. It contains only ca.crt,
never a private key, and it spans a CA rollover. That is exactly the
trust anchor the tenant needs, and it already exists in the namespace,
so grant it to the tenant instead of stating that no CA is available.
The previous wording told operators to skip verification or to turn
enforcement off, which weakened security to work around a problem that
was not real.
Point the backup job at the bundle too. It was projecting ca.crt out of
the leaf Secret, which only ever holds the CA that signed the current
certificate and needlessly couples backups to leaf rotation.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Enabling TLS sets require_secure_transport=ON, and external instances
get that automatically, so every plaintext client stops connecting the
moment the change lands. Nothing user-facing said so, and the recovery
HowTo still gave commands that fail against a TLS-enforcing server.
Describe how to connect with verification, note that the verification
flags are MariaDB spellings rather than the MySQL ones, state that CA
distribution to the tenant is not available yet, and give the staged
migration using tls.required: false for instances that already have
clients.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The headless wildcard was listed at three resolution depths while every
named service was listed at four. A client resolving the missing
3-label form presents that name during the handshake, and a SAN gap
fails verification, so the wildcard now covers the same depths as the
rest of the list.
The external hostname was also read straight off _namespace, which
raises a raw nil pointer error naming neither the value nor the reason
when the key is absent. Route it through required, and tolerate an
absent or null _namespace so the explanatory message is what surfaces
rather than an index error.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The target was defined three times, so make emitted an override warning
on every invocation and the last definition silently won. All three
recipes were identical, so collapsing them to the one declared .PHONY
changes no behaviour.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The tenant needs the CA certificate to verify TLS connections, but the
cert-manager Secrets that back the chain are key-bearing: <name>-ca-tls
holds the CA private key and <name>-tls holds the server private key.
The dashboard Role granted the tenant read access to both whenever TLS
was on, which handed out signing material where only a trust anchor was
required.
Drop both from the tenant grant and mark the CA Secret as the source of
a key-free projection instead. The chart owns the cert-manager chain
here, so it labels the CA Secret directly, inside the existing TLS gate:
with TLS disabled the chain is not rendered and nothing is marked. Only
the CA carries the labels, never the leaf.
The selector added to the ApplicationDefinition is deliberately specific.
An empty selector would compile to a match-everything label selector and
project every Secret in the namespace to the tenant.
The source Secret and the projection are matched by two different
labels on purpose: the source stays key-bearing and internal, while the
published copy is key-free. Selecting the source directly from the
consumer would defeat the split and leak the CA private key.
Note that the labels and the selector are inert until the controller
that produces the projection exists: nothing reads the labels yet, and
the selector matches no Secret.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The backup image is alpine plus mariadb-client, so the backup script is
parsed by the MariaDB client. That client implements no ssl-mode option:
it is MySQL 8 syntax, and the MariaDB client rejects it while parsing
arguments ("unknown variable", exit 7) before it ever opens a
connection. Every TLS-enabled backup run therefore failed at the first
client invocation.
Replace it with the MariaDB equivalent, --ssl-ca combined with
--ssl-verify-server-cert, which validates the chain against the CA and
checks the server hostname against the certificate SANs.
Also align the cluster-domain fallback in the certificate template with
the rest of the catalog, which defaults to cozy.local rather than the
upstream Kubernetes cluster.local. These names go into the leaf
certificate SAN list that the backup client now verifies against, so a
mismatched fallback would produce certificates that fail hostname
verification.
The previous assertions only checked that an SSL string appeared in the
rendered script, so they stayed green against a script the client
refuses to parse. They now pin the client dialect instead: the MariaDB
verification flags must be present, the MySQL-only option must never be
emitted in any TLS state, and both client invocations must carry the
options.
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The tls.enabled field was previously patched in the Makefile via jq to
emit "type": ["boolean","null"], which breaks cozystack-api's
apiextv1.JSONSchemaProps.Type (single string field) and silently
disables server-side defaulting.
cozyvalues-gen correctly emits "type": "boolean" from the @param {*bool}
annotation. The jq patch and its precondition/postcondition checks are
no longer needed and are removed from the Makefile.
The tri-state behavior (unset tls.enabled inherits external) is
preserved through the kindIs "invalid" check in the _tls.tpl helper,
which catches the unset case. Explicitly passing null is rejected by
schema validation, which is the correct behavior for a boolean field.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
When mariadb-operator sets require_secure_transport=ON (tls.required:
true), the server rejects plaintext TCP connections. The backup CronJob
used plain mysql and mysqldump commands with no SSL flags, causing all
backups to fail silently.
The leaf certificate SAN list already covers the primary and secondary
service names that the backup uses via MYSQL_HOST, so
--ssl-mode=VERIFY_IDENTITY (strictest mode with hostname validation)
is correct here.
The fix conditionally adds:
- SSL_OPTS variable in the backup script with --ssl-ca and --ssl-mode
- A tls-ca volume mounting ca.crt from the leaf TLS Secret
- A corresponding volumeMount at /etc/mysql-ssl in the backup container
The TLS path is activated through the same mariadb.tls.enabled helper
used elsewhere in the chart, so it follows the external inheritance
tri-state correctly.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
ECDSA P-256 keys offer equivalent or better security than RSA-4096 with
significantly smaller key material and faster handshake operations. Both
CA and leaf certificates are updated; existing rotation policies are
preserved (Never for CA, Always for leaf).
Note: cert-manager will re-issue both CA and leaf on next reconcile.
Existing trust anchors that pin the CA cert will break; tenants must
refresh their ca.crt after upgrading.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Some DNS clients shorten hostnames before resolving them based on the
ndots setting. For example, a client inside the same namespace with
ndots:5 may try "svc-name.namespace" before the full
"svc-name.namespace.svc.cluster.local" form. Without the short-form
SANs in the certificate, the TLS handshake fails for those clients
even though they reach the correct endpoint.
Adds "*.name-internal" and "name.namespace" (without .svc suffix)
variants to the leaf certificate SAN list.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Adds the crl sign key usage to the CA certificate for conventional
compliance with RFC 5280. CA certificates that may sign CRLs should
advertise this usage even when CRL distribution is not currently
configured.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
TLS 1.3 and TLS 1.2 ECDHE require the server certificate to have the
digital signature key usage so that ephemeral key-exchange parameters
can be signed. Without it, strict TLS stacks (Go crypto/tls, BoringSSL)
reject the handshake at the ServerKeyExchange step.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
The leaf cert now covers the base ClusterIP service `<release>` alongside
the existing `-primary` and `-secondary` services so a client connection
that uses the unqualified release name (e.g. via cozystack platform DNS)
passes hostname verification. The headless `-internal` wildcard and the
external LoadBalancer hostname are unaffected.
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Add a @section Version parameters marker in values.yaml so that the version
parameter is grouped separately from TLS parameters in the generated README
and schema. Explicitly set tls.required: true in values.yaml so UI clients
and schema consumers see the correct default (true, matching the template
behaviour documented in the description field). Also add
[\"spec\",\"tls\",\"enabled\"] and [\"spec\",\"tls\",\"required\"] to keysOrder in
mariadb-rd so TLS child fields render in a stable order in the dashboard.
Regenerate codegen artifacts accordingly.
Assisted-by: LLM
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Run root and per-package make generate to bring deepcopy, types, README, and CRD
descriptor in sync with values.yaml annotations after the TLS work landed.
Signed-off-by: Arsolitt <arsolitt@gmail.com>