1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-03-31 04:14:59 +00:00

Merge pull request #7149 from mviswanathsai/alertmanager-mtls

Feature: Enable configuring mTLS (ClusterTLS) in AlertManager
This commit is contained in:
M Viswanath Sai 2025-03-11 13:33:27 +05:30 committed by GitHub
parent 9da5dce39d
commit e61abf1b84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 2755 additions and 85 deletions

View file

@ -789,6 +789,21 @@ AlertmanagerWebSpec
</tr>
<tr>
<td>
<code>clusterTLS</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.ClusterTLSConfig">
ClusterTLSConfig
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Configures the mutual TLS configuration for the Alertmanager cluster&rsquo;s gossip protocol.</p>
<p>It requires Alertmanager &gt;= 0.24.0.</p>
</td>
</tr>
<tr>
<td>
<code>alertmanagerConfiguration</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.AlertmanagerConfiguration">
@ -6253,6 +6268,21 @@ AlertmanagerWebSpec
</tr>
<tr>
<td>
<code>clusterTLS</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.ClusterTLSConfig">
ClusterTLSConfig
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Configures the mutual TLS configuration for the Alertmanager cluster&rsquo;s gossip protocol.</p>
<p>It requires Alertmanager &gt;= 0.24.0.</p>
</td>
</tr>
<tr>
<td>
<code>alertmanagerConfiguration</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.AlertmanagerConfiguration">
@ -6876,6 +6906,50 @@ authentication.</p>
<p>ByteSize is a valid memory size type based on powers-of-2, so 1KB is 1024B.
Supported units: B, KB, KiB, MB, MiB, GB, GiB, TB, TiB, PB, PiB, EB, EiB Ex: <code>512MB</code>.</p>
</div>
<h3 id="monitoring.coreos.com/v1.ClusterTLSConfig">ClusterTLSConfig
</h3>
<p>
(<em>Appears on:</em><a href="#monitoring.coreos.com/v1.AlertmanagerSpec">AlertmanagerSpec</a>)
</p>
<div>
<p>ClusterTLSConfig defines the mutual TLS configuration for the Alertmanager cluster TLS protocol.</p>
</div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>server</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.WebTLSConfig">
WebTLSConfig
</a>
</em>
</td>
<td>
<p>Server-side configuration for mutual TLS.</p>
</td>
</tr>
<tr>
<td>
<code>client</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.SafeTLSConfig">
SafeTLSConfig
</a>
</em>
</td>
<td>
<p>Client-side configuration for mutual TLS.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="monitoring.coreos.com/v1.CommonPrometheusFields">CommonPrometheusFields
</h3>
<p>
@ -15440,7 +15514,7 @@ Kubernetes core/v1.SecretKeySelector
<h3 id="monitoring.coreos.com/v1.SafeTLSConfig">SafeTLSConfig
</h3>
<p>
(<em>Appears on:</em><a href="#monitoring.coreos.com/v1.HTTPConfig">HTTPConfig</a>, <a href="#monitoring.coreos.com/v1.OAuth2">OAuth2</a>, <a href="#monitoring.coreos.com/v1.PodMetricsEndpoint">PodMetricsEndpoint</a>, <a href="#monitoring.coreos.com/v1.ProbeSpec">ProbeSpec</a>, <a href="#monitoring.coreos.com/v1.TLSConfig">TLSConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.AzureSDConfig">AzureSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.ConsulSDConfig">ConsulSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.DigitalOceanSDConfig">DigitalOceanSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.DockerSDConfig">DockerSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.DockerSwarmSDConfig">DockerSwarmSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.EC2SDConfig">EC2SDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.EmailConfig">EmailConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.EurekaSDConfig">EurekaSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.HTTPConfig">HTTPConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.HTTPSDConfig">HTTPSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.HetznerSDConfig">HetznerSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.IonosSDConfig">IonosSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.KubernetesSDConfig">KubernetesSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.KumaSDConfig">KumaSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.LightSailSDConfig">LightSailSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.LinodeSDConfig">LinodeSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.NomadSDConfig">NomadSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.OpenStackSDConfig">OpenStackSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.PuppetDBSDConfig">PuppetDBSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.ScalewaySDConfig">ScalewaySDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.ScrapeConfigSpec">ScrapeConfigSpec</a>, <a href="#monitoring.coreos.com/v1beta1.EmailConfig">EmailConfig</a>, <a href="#monitoring.coreos.com/v1beta1.HTTPConfig">HTTPConfig</a>)
(<em>Appears on:</em><a href="#monitoring.coreos.com/v1.ClusterTLSConfig">ClusterTLSConfig</a>, <a href="#monitoring.coreos.com/v1.HTTPConfig">HTTPConfig</a>, <a href="#monitoring.coreos.com/v1.OAuth2">OAuth2</a>, <a href="#monitoring.coreos.com/v1.PodMetricsEndpoint">PodMetricsEndpoint</a>, <a href="#monitoring.coreos.com/v1.ProbeSpec">ProbeSpec</a>, <a href="#monitoring.coreos.com/v1.TLSConfig">TLSConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.AzureSDConfig">AzureSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.ConsulSDConfig">ConsulSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.DigitalOceanSDConfig">DigitalOceanSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.DockerSDConfig">DockerSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.DockerSwarmSDConfig">DockerSwarmSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.EC2SDConfig">EC2SDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.EmailConfig">EmailConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.EurekaSDConfig">EurekaSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.HTTPConfig">HTTPConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.HTTPSDConfig">HTTPSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.HetznerSDConfig">HetznerSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.IonosSDConfig">IonosSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.KubernetesSDConfig">KubernetesSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.KumaSDConfig">KumaSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.LightSailSDConfig">LightSailSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.LinodeSDConfig">LinodeSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.NomadSDConfig">NomadSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.OpenStackSDConfig">OpenStackSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.PuppetDBSDConfig">PuppetDBSDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.ScalewaySDConfig">ScalewaySDConfig</a>, <a href="#monitoring.coreos.com/v1alpha1.ScrapeConfigSpec">ScrapeConfigSpec</a>, <a href="#monitoring.coreos.com/v1beta1.EmailConfig">EmailConfig</a>, <a href="#monitoring.coreos.com/v1beta1.HTTPConfig">HTTPConfig</a>)
</p>
<div>
<p>SafeTLSConfig specifies safe TLS configuration parameters.</p>
@ -18313,7 +18387,7 @@ domain and subdomains over HTTPS.
<h3 id="monitoring.coreos.com/v1.WebTLSConfig">WebTLSConfig
</h3>
<p>
(<em>Appears on:</em><a href="#monitoring.coreos.com/v1.WebConfigFileFields">WebConfigFileFields</a>)
(<em>Appears on:</em><a href="#monitoring.coreos.com/v1.ClusterTLSConfig">ClusterTLSConfig</a>, <a href="#monitoring.coreos.com/v1.WebConfigFileFields">WebConfigFileFields</a>)
</p>
<div>
<p>WebTLSConfig defines the TLS parameters for HTTPS.</p>

View file

@ -60,6 +60,8 @@ K8S_GEN_DEPS+=$(TYPES_V1ALPHA1_TARGET)
K8S_GEN_DEPS+=$(TYPES_V1BETA1_TARGET)
K8S_GEN_DEPS+=$(foreach bin,$(K8S_GEN_BINARIES),$(TOOLS_BIN_DIR)/$(bin))
CERTS_DIR := test/e2e/tls_certs
BUILD_DATE=$(shell date +"%Y%m%d-%T")
# source: https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables#default-environment-variables
ifndef GITHUB_ACTIONS
@ -236,9 +238,9 @@ generate-crds: $(CONTROLLER_GEN_BINARY) $(GOJSONTOYAML_BINARY) $(TYPES_V1_TARGET
echo "// Code generated using 'make generate-crds'. DO NOT EDIT." > $(PWD)/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet
echo "{spec+: {versions+: $$($(GOJSONTOYAML_BINARY) -yamltojson < example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagerconfigs.yaml | jq '.spec.versions | map(select(.name == "v1beta1"))')}}" | $(JSONNETFMT_BINARY) - >> $(PWD)/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet
.PHONY: generate-remote-write-certs
generate-remote-write-certs:
mkdir -p test/e2e/remote_write_certs && \
.PHONY: generate-tls-certs
generate-tls-certs:
mkdir -p $(CERTS_DIR) && \
(cd scripts && GOOS=$(OS) GOARCH=$(GOARCH) go run -v ./certs/.)
.PHONY: generate-docs
@ -360,8 +362,8 @@ test-unit-update-golden:
test/instrumented-sample-app/certs/cert.pem test/instrumented-sample-app/certs/key.pem:
cd test/instrumented-sample-app && make generate-certs
test/e2e/remote_write_certs/ca.key test/e2e/remote_write_certs/ca.crt test/e2e/remote_write_certs/client.key test/e2e/remote_write_certs/client.crt test/e2e/remote_write_certs/bad_ca.key test/e2e/remote_write_certs/bad_ca.crt test/e2e/remote_write_certs/bad_client.key test/e2e/remote_write_certs/bad_client.crt:
$(MAKE) generate-remote-write-certs
$(CERTS_DIR)/ca.key $(CERTS_DIR)/ca.crt $(CERTS_DIR)/client.key $(CERTS_DIR)/client.crt $(CERTS_DIR)/bad_ca.key $(CERTS_DIR)/bad_ca.crt $(CERTS_DIR)/bad_client.key $(CERTS_DIR)/bad_client.crt:
$(MAKE) generate-tls-certs
.PHONY: test-e2e
test-e2e: KUBECONFIG?=$(HOME)/.kube/config

382
bundle.yaml generated
View file

@ -12121,6 +12121,388 @@ spec:
description: Interval between pushpull attempts.
pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
clusterTLS:
description: |-
Configures the mutual TLS configuration for the Alertmanager cluster's gossip protocol.
It requires Alertmanager >= 0.24.0.
properties:
client:
description: Client-side configuration for mutual TLS.
properties:
ca:
description: Certificate authority used when verifying server
certificates.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
cert:
description: Client certificate to present when doing client-authentication.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
insecureSkipVerify:
description: Disable target certificate validation.
type: boolean
keySecret:
description: Secret containing the client key file for the
targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
maxVersion:
description: |-
Maximum acceptable TLS version.
It requires Prometheus >= v2.41.0.
enum:
- TLS10
- TLS11
- TLS12
- TLS13
type: string
minVersion:
description: |-
Minimum acceptable TLS version.
It requires Prometheus >= v2.35.0.
enum:
- TLS10
- TLS11
- TLS12
- TLS13
type: string
serverName:
description: Used to verify the hostname for the targets.
type: string
type: object
server:
description: Server-side configuration for mutual TLS.
properties:
cert:
description: |-
Secret or ConfigMap containing the TLS certificate for the web server.
Either `keySecret` or `keyFile` must be defined.
It is mutually exclusive with `certFile`.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
certFile:
description: |-
Path to the TLS certificate file in the container for the web server.
Either `keySecret` or `keyFile` must be defined.
It is mutually exclusive with `cert`.
type: string
cipherSuites:
description: |-
List of supported cipher suites for TLS versions up to TLS 1.2.
If not defined, the Go default cipher suites are used.
Available cipher suites are documented in the Go documentation:
https://golang.org/pkg/crypto/tls/#pkg-constants
items:
type: string
type: array
client_ca:
description: |-
Secret or ConfigMap containing the CA certificate for client certificate
authentication to the server.
It is mutually exclusive with `clientCAFile`.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
clientAuthType:
description: |-
The server policy for client TLS authentication.
For more detail on clientAuth options:
https://golang.org/pkg/crypto/tls/#ClientAuthType
type: string
clientCAFile:
description: |-
Path to the CA certificate file for client certificate authentication to
the server.
It is mutually exclusive with `client_ca`.
type: string
curvePreferences:
description: |-
Elliptic curves that will be used in an ECDHE handshake, in preference
order.
Available curves are documented in the Go documentation:
https://golang.org/pkg/crypto/tls/#CurveID
items:
type: string
type: array
keyFile:
description: |-
Path to the TLS private key file in the container for the web server.
If defined, either `cert` or `certFile` must be defined.
It is mutually exclusive with `keySecret`.
type: string
keySecret:
description: |-
Secret containing the TLS private key for the web server.
Either `cert` or `certFile` must be defined.
It is mutually exclusive with `keyFile`.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
maxVersion:
description: Maximum TLS version that is acceptable.
type: string
minVersion:
description: Minimum TLS version that is acceptable.
type: string
preferServerCipherSuites:
description: |-
Controls whether the server selects the client's most preferred cipher
suite, or the server's most preferred cipher suite.
If true then the server's preference, as expressed in
the order of elements in cipherSuites, is used.
type: boolean
type: object
required:
- client
- server
type: object
configMaps:
description: |-
ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager

View file

@ -2082,6 +2082,388 @@ spec:
description: Interval between pushpull attempts.
pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
clusterTLS:
description: |-
Configures the mutual TLS configuration for the Alertmanager cluster's gossip protocol.
It requires Alertmanager >= 0.24.0.
properties:
client:
description: Client-side configuration for mutual TLS.
properties:
ca:
description: Certificate authority used when verifying server
certificates.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
cert:
description: Client certificate to present when doing client-authentication.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
insecureSkipVerify:
description: Disable target certificate validation.
type: boolean
keySecret:
description: Secret containing the client key file for the
targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
maxVersion:
description: |-
Maximum acceptable TLS version.
It requires Prometheus >= v2.41.0.
enum:
- TLS10
- TLS11
- TLS12
- TLS13
type: string
minVersion:
description: |-
Minimum acceptable TLS version.
It requires Prometheus >= v2.35.0.
enum:
- TLS10
- TLS11
- TLS12
- TLS13
type: string
serverName:
description: Used to verify the hostname for the targets.
type: string
type: object
server:
description: Server-side configuration for mutual TLS.
properties:
cert:
description: |-
Secret or ConfigMap containing the TLS certificate for the web server.
Either `keySecret` or `keyFile` must be defined.
It is mutually exclusive with `certFile`.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
certFile:
description: |-
Path to the TLS certificate file in the container for the web server.
Either `keySecret` or `keyFile` must be defined.
It is mutually exclusive with `cert`.
type: string
cipherSuites:
description: |-
List of supported cipher suites for TLS versions up to TLS 1.2.
If not defined, the Go default cipher suites are used.
Available cipher suites are documented in the Go documentation:
https://golang.org/pkg/crypto/tls/#pkg-constants
items:
type: string
type: array
client_ca:
description: |-
Secret or ConfigMap containing the CA certificate for client certificate
authentication to the server.
It is mutually exclusive with `clientCAFile`.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
clientAuthType:
description: |-
The server policy for client TLS authentication.
For more detail on clientAuth options:
https://golang.org/pkg/crypto/tls/#ClientAuthType
type: string
clientCAFile:
description: |-
Path to the CA certificate file for client certificate authentication to
the server.
It is mutually exclusive with `client_ca`.
type: string
curvePreferences:
description: |-
Elliptic curves that will be used in an ECDHE handshake, in preference
order.
Available curves are documented in the Go documentation:
https://golang.org/pkg/crypto/tls/#CurveID
items:
type: string
type: array
keyFile:
description: |-
Path to the TLS private key file in the container for the web server.
If defined, either `cert` or `certFile` must be defined.
It is mutually exclusive with `keySecret`.
type: string
keySecret:
description: |-
Secret containing the TLS private key for the web server.
Either `cert` or `certFile` must be defined.
It is mutually exclusive with `keyFile`.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
maxVersion:
description: Maximum TLS version that is acceptable.
type: string
minVersion:
description: Minimum TLS version that is acceptable.
type: string
preferServerCipherSuites:
description: |-
Controls whether the server selects the client's most preferred cipher
suite, or the server's most preferred cipher suite.
If true then the server's preference, as expressed in
the order of elements in cipherSuites, is used.
type: boolean
type: object
required:
- client
- server
type: object
configMaps:
description: |-
ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager

View file

@ -2083,6 +2083,388 @@ spec:
description: Interval between pushpull attempts.
pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
type: string
clusterTLS:
description: |-
Configures the mutual TLS configuration for the Alertmanager cluster's gossip protocol.
It requires Alertmanager >= 0.24.0.
properties:
client:
description: Client-side configuration for mutual TLS.
properties:
ca:
description: Certificate authority used when verifying server
certificates.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
cert:
description: Client certificate to present when doing client-authentication.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
insecureSkipVerify:
description: Disable target certificate validation.
type: boolean
keySecret:
description: Secret containing the client key file for the
targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
maxVersion:
description: |-
Maximum acceptable TLS version.
It requires Prometheus >= v2.41.0.
enum:
- TLS10
- TLS11
- TLS12
- TLS13
type: string
minVersion:
description: |-
Minimum acceptable TLS version.
It requires Prometheus >= v2.35.0.
enum:
- TLS10
- TLS11
- TLS12
- TLS13
type: string
serverName:
description: Used to verify the hostname for the targets.
type: string
type: object
server:
description: Server-side configuration for mutual TLS.
properties:
cert:
description: |-
Secret or ConfigMap containing the TLS certificate for the web server.
Either `keySecret` or `keyFile` must be defined.
It is mutually exclusive with `certFile`.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
certFile:
description: |-
Path to the TLS certificate file in the container for the web server.
Either `keySecret` or `keyFile` must be defined.
It is mutually exclusive with `cert`.
type: string
cipherSuites:
description: |-
List of supported cipher suites for TLS versions up to TLS 1.2.
If not defined, the Go default cipher suites are used.
Available cipher suites are documented in the Go documentation:
https://golang.org/pkg/crypto/tls/#pkg-constants
items:
type: string
type: array
client_ca:
description: |-
Secret or ConfigMap containing the CA certificate for client certificate
authentication to the server.
It is mutually exclusive with `clientCAFile`.
properties:
configMap:
description: ConfigMap containing data to use for the
targets.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
secret:
description: Secret containing data to use for the targets.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
clientAuthType:
description: |-
The server policy for client TLS authentication.
For more detail on clientAuth options:
https://golang.org/pkg/crypto/tls/#ClientAuthType
type: string
clientCAFile:
description: |-
Path to the CA certificate file for client certificate authentication to
the server.
It is mutually exclusive with `client_ca`.
type: string
curvePreferences:
description: |-
Elliptic curves that will be used in an ECDHE handshake, in preference
order.
Available curves are documented in the Go documentation:
https://golang.org/pkg/crypto/tls/#CurveID
items:
type: string
type: array
keyFile:
description: |-
Path to the TLS private key file in the container for the web server.
If defined, either `cert` or `certFile` must be defined.
It is mutually exclusive with `keySecret`.
type: string
keySecret:
description: |-
Secret containing the TLS private key for the web server.
Either `cert` or `certFile` must be defined.
It is mutually exclusive with `keyFile`.
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
maxVersion:
description: Maximum TLS version that is acceptable.
type: string
minVersion:
description: Minimum TLS version that is acceptable.
type: string
preferServerCipherSuites:
description: |-
Controls whether the server selects the client's most preferred cipher
suite, or the server's most preferred cipher suite.
If true then the server's preference, as expressed in
the order of elements in cipherSuites, is used.
type: boolean
type: object
required:
- client
- server
type: object
configMaps:
description: |-
ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager

View file

@ -1860,6 +1860,352 @@
"pattern": "^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$",
"type": "string"
},
"clusterTLS": {
"description": "Configures the mutual TLS configuration for the Alertmanager cluster's gossip protocol.\n\nIt requires Alertmanager >= 0.24.0.",
"properties": {
"client": {
"description": "Client-side configuration for mutual TLS.",
"properties": {
"ca": {
"description": "Certificate authority used when verifying server certificates.",
"properties": {
"configMap": {
"description": "ConfigMap containing data to use for the targets.",
"properties": {
"key": {
"description": "The key to select.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the ConfigMap or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secret": {
"description": "Secret containing data to use for the targets.",
"properties": {
"key": {
"description": "The key of the secret to select from. Must be a valid secret key.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
},
"cert": {
"description": "Client certificate to present when doing client-authentication.",
"properties": {
"configMap": {
"description": "ConfigMap containing data to use for the targets.",
"properties": {
"key": {
"description": "The key to select.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the ConfigMap or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secret": {
"description": "Secret containing data to use for the targets.",
"properties": {
"key": {
"description": "The key of the secret to select from. Must be a valid secret key.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
},
"insecureSkipVerify": {
"description": "Disable target certificate validation.",
"type": "boolean"
},
"keySecret": {
"description": "Secret containing the client key file for the targets.",
"properties": {
"key": {
"description": "The key of the secret to select from. Must be a valid secret key.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"maxVersion": {
"description": "Maximum acceptable TLS version.\n\nIt requires Prometheus >= v2.41.0.",
"enum": [
"TLS10",
"TLS11",
"TLS12",
"TLS13"
],
"type": "string"
},
"minVersion": {
"description": "Minimum acceptable TLS version.\n\nIt requires Prometheus >= v2.35.0.",
"enum": [
"TLS10",
"TLS11",
"TLS12",
"TLS13"
],
"type": "string"
},
"serverName": {
"description": "Used to verify the hostname for the targets.",
"type": "string"
}
},
"type": "object"
},
"server": {
"description": "Server-side configuration for mutual TLS.",
"properties": {
"cert": {
"description": "Secret or ConfigMap containing the TLS certificate for the web server.\n\nEither `keySecret` or `keyFile` must be defined.\n\nIt is mutually exclusive with `certFile`.",
"properties": {
"configMap": {
"description": "ConfigMap containing data to use for the targets.",
"properties": {
"key": {
"description": "The key to select.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the ConfigMap or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secret": {
"description": "Secret containing data to use for the targets.",
"properties": {
"key": {
"description": "The key of the secret to select from. Must be a valid secret key.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
},
"certFile": {
"description": "Path to the TLS certificate file in the container for the web server.\n\nEither `keySecret` or `keyFile` must be defined.\n\nIt is mutually exclusive with `cert`.",
"type": "string"
},
"cipherSuites": {
"description": "List of supported cipher suites for TLS versions up to TLS 1.2.\n\nIf not defined, the Go default cipher suites are used.\nAvailable cipher suites are documented in the Go documentation:\nhttps://golang.org/pkg/crypto/tls/#pkg-constants",
"items": {
"type": "string"
},
"type": "array"
},
"clientAuthType": {
"description": "The server policy for client TLS authentication.\n\nFor more detail on clientAuth options:\nhttps://golang.org/pkg/crypto/tls/#ClientAuthType",
"type": "string"
},
"clientCAFile": {
"description": "Path to the CA certificate file for client certificate authentication to\nthe server.\n\nIt is mutually exclusive with `client_ca`.",
"type": "string"
},
"client_ca": {
"description": "Secret or ConfigMap containing the CA certificate for client certificate\nauthentication to the server.\n\nIt is mutually exclusive with `clientCAFile`.",
"properties": {
"configMap": {
"description": "ConfigMap containing data to use for the targets.",
"properties": {
"key": {
"description": "The key to select.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the ConfigMap or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secret": {
"description": "Secret containing data to use for the targets.",
"properties": {
"key": {
"description": "The key of the secret to select from. Must be a valid secret key.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
},
"curvePreferences": {
"description": "Elliptic curves that will be used in an ECDHE handshake, in preference\norder.\n\nAvailable curves are documented in the Go documentation:\nhttps://golang.org/pkg/crypto/tls/#CurveID",
"items": {
"type": "string"
},
"type": "array"
},
"keyFile": {
"description": "Path to the TLS private key file in the container for the web server.\n\nIf defined, either `cert` or `certFile` must be defined.\n\nIt is mutually exclusive with `keySecret`.",
"type": "string"
},
"keySecret": {
"description": "Secret containing the TLS private key for the web server.\n\nEither `cert` or `certFile` must be defined.\n\nIt is mutually exclusive with `keyFile`.",
"properties": {
"key": {
"description": "The key of the secret to select from. Must be a valid secret key.",
"type": "string"
},
"name": {
"default": "",
"description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"maxVersion": {
"description": "Maximum TLS version that is acceptable.",
"type": "string"
},
"minVersion": {
"description": "Minimum TLS version that is acceptable.",
"type": "string"
},
"preferServerCipherSuites": {
"description": "Controls whether the server selects the client's most preferred cipher\nsuite, or the server's most preferred cipher suite.\n\nIf true then the server's preference, as expressed in\nthe order of elements in cipherSuites, is used.",
"type": "boolean"
}
},
"type": "object"
}
},
"required": [
"client",
"server"
],
"type": "object"
},
"configMaps": {
"description": "ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager\nobject, which shall be mounted into the Alertmanager Pods.\nEach ConfigMap is added to the StatefulSet definition as a volume named `configmap-<configmap-name>`.\nThe ConfigMaps are mounted into `/etc/alertmanager/configmaps/<configmap-name>` in the 'alertmanager' container.",
"items": {

View file

@ -0,0 +1,300 @@
// Copyright 2024 The prometheus-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package clustertlsconfig
import (
"fmt"
"path"
"path/filepath"
"gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
webconfig "github.com/prometheus-operator/prometheus-operator/pkg/webconfig"
)
const (
cmdflag = "cluster.tls-config"
volumeName = "cluster-tls-config"
serverVolumePrefix = "cluster-tls-server-config-"
clientVolumePrefix = "cluster-tls-client-config-"
serverTLSCredDir = "server_tls"
clientTLSCredDir = "client_tls"
ConfigFileKey = "cluster-tls-config.yaml"
)
// Config is the web configuration for prometheus and alertmanager instance.
//
// Config can make a secret which holds the web config contents, as well as
// volumes and volume mounts for referencing the secret and the
// necessary TLS credentials.
type Config struct {
clusterTLSConfig *monitoringv1.ClusterTLSConfig
serverTLSReferences *webconfig.TLSReferences
clientTLSReferences *webconfig.TLSReferences
mountingDir string
secretName string
}
// New creates a new ClusterTLSConfig.
// All volumes related to the cluster TLS config will be mounted via the `mountingDir`.
// The Secret where the cluster TLS config will be stored will be named `secretName`.
// All volumes containing TLS credentials related to cluster TLS configuration will be prefixed with "cluster-tls-server-config-"
// or "cluster-tls-client-config-" respectively, for server and client credentials.
func New(mountingDir string, secretName string, clusterTLSConfig *monitoringv1.ClusterTLSConfig) (*Config, error) {
if clusterTLSConfig == nil {
return &Config{
mountingDir: mountingDir,
secretName: secretName,
}, nil
}
var (
clientTLSCreds *webconfig.TLSReferences
serverTLSCreds *webconfig.TLSReferences
)
serverTLSConfig := clusterTLSConfig.ServerTLS
if err := serverTLSConfig.Validate(); err != nil {
return nil, err
}
clientTLSConfig := clusterTLSConfig.ClientTLS
if err := clientTLSConfig.Validate(); err != nil {
return nil, err
}
serverTLSCreds = webconfig.NewTLSReferences(path.Join(mountingDir, serverTLSCredDir), serverTLSConfig.KeySecret, serverTLSConfig.Cert, serverTLSConfig.ClientCA)
clientTLSCreds = webconfig.NewTLSReferences(path.Join(mountingDir, clientTLSCredDir), *clientTLSConfig.KeySecret, clientTLSConfig.Cert, clientTLSConfig.CA)
return &Config{
clusterTLSConfig: clusterTLSConfig,
serverTLSReferences: serverTLSCreds,
clientTLSReferences: clientTLSCreds,
mountingDir: mountingDir,
secretName: secretName,
}, nil
}
// GetMountParameters returns volumes and volume mounts referencing the cluster TLS config file
// and the associated TLS credentials.
// In addition, GetMountParameters returns a cluster.tls-config command line option pointing
// to the cluster TLS config file in the volume mount.
// All TLS credentials related to cluster TLS configuration will be prefixed with "cluster-tls-server-config-"
// or "cluster-tls-client-config-" respectively, for server and client credentials.
// The server and client TLS credentials are mounted in different paths: ~/{mountingDir}/server-tls/
// and ~/{mountingDir}/client-tls/ respectively.
func (c Config) GetMountParameters() (*monitoringv1.Argument, []v1.Volume, []v1.VolumeMount, error) {
destinationPath := path.Join(c.mountingDir, ConfigFileKey)
var volumes []v1.Volume
var mounts []v1.VolumeMount
var arg *monitoringv1.Argument
// Only return an argument if the cluster TLS config and it's server component are defined.
if c.clusterTLSConfig != nil {
arg = c.makeArg(destinationPath)
}
cfgVolume := c.makeVolume()
volumes = append(volumes, cfgVolume)
cfgMount := c.makeVolumeMount(destinationPath)
mounts = append(mounts, cfgMount)
if c.serverTLSReferences != nil {
servertlsVolumes, servertlsMounts, err := c.serverTLSReferences.GetMountParameters(serverVolumePrefix)
if err != nil {
return &monitoringv1.Argument{}, nil, nil, err
}
volumes = append(volumes, servertlsVolumes...)
mounts = append(mounts, servertlsMounts...)
}
if c.clientTLSReferences != nil {
clienttlsVolumes, clienttlsMounts, err := c.clientTLSReferences.GetMountParameters(clientVolumePrefix)
if err != nil {
return &monitoringv1.Argument{}, nil, nil, err
}
volumes = append(volumes, clienttlsVolumes...)
mounts = append(mounts, clienttlsMounts...)
}
return arg, volumes, mounts, nil
}
// CreateOrUpdateConfigSecret create or update a Kubernetes secret with the data for the cluster TLS config file.
// The format of the cluster TLS config file is available in the official prometheus documentation:
// https://github.com/prometheus/alertmanager/blob/main/docs/https.md#gossip-traffic/
func (c Config) ClusterTLSConfiguration() ([]byte, error) {
if c.clusterTLSConfig == nil {
return []byte{}, nil
}
data, err := c.generateConfigFileContents()
if err != nil {
return nil, err
}
return data, nil
}
// generateConfigFileContents() generates the contents of cluster-tls-config.yaml
// from the Config in the form of an array of bytes.
func (c Config) generateConfigFileContents() ([]byte, error) {
cfg := yaml.MapSlice{}
cfg = c.addServerTLSConfigToYaml(cfg)
cfg = c.addClientTLSConfigToYaml(cfg)
return yaml.Marshal(cfg)
}
// makeArg() returns an argument with the name "cluster.tls-config" with the filePath
// as its value.
func (c Config) makeArg(filePath string) *monitoringv1.Argument {
return &monitoringv1.Argument{Name: cmdflag, Value: filePath}
}
// makeVolume() creates a Volume with volumeName = "cluster-tls-config" which stores
// the secret which contains the cluster TLS config.
func (c Config) makeVolume() v1.Volume {
return v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: c.secretName,
},
},
}
}
// makeVolumeMount() creates a VolumeMount, mounting the cluster_tls_config.yaml SubPath
// to the given filePath.
func (c Config) makeVolumeMount(filePath string) v1.VolumeMount {
return v1.VolumeMount{
Name: volumeName,
SubPath: ConfigFileKey,
ReadOnly: true,
MountPath: filePath,
}
}
func (c Config) GetSecretName() string {
return c.secretName
}
func (c Config) addServerTLSConfigToYaml(cfg yaml.MapSlice) yaml.MapSlice {
tls := c.clusterTLSConfig.ServerTLS
mtlsServerConfig := yaml.MapSlice{}
tlsRefs := c.serverTLSReferences
switch {
case ptr.Deref(tls.KeyFile, "") != "":
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "key_file", Value: *tls.KeyFile})
case tlsRefs.GetKeyMountPath() != "":
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "key_file", Value: filepath.Join(tlsRefs.GetKeyMountPath(), tlsRefs.GetKeyFilename())})
}
switch {
case ptr.Deref(tls.CertFile, "") != "":
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "cert_file", Value: *tls.CertFile})
case tlsRefs.GetCertMountPath() != "":
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "cert_file", Value: filepath.Join(tlsRefs.GetCertMountPath(), tlsRefs.GetCertFilename())})
}
if ptr.Deref(tls.ClientAuthType, "") != "" {
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
Key: "client_auth_type",
Value: *tls.ClientAuthType,
})
}
switch {
case ptr.Deref(tls.ClientCAFile, "") != "":
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: *tls.ClientCAFile})
case tlsRefs.GetCAMountPath() != "":
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: filepath.Join(tlsRefs.GetCAMountPath(), tlsRefs.GetCAFilename())})
}
if ptr.Deref(tls.MinVersion, "") != "" {
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
Key: "min_version",
Value: *tls.MinVersion,
})
}
if ptr.Deref(tls.MaxVersion, "") != "" {
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
Key: "max_version",
Value: *tls.MaxVersion,
})
}
if len(tls.CipherSuites) != 0 {
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
Key: "cipher_suites",
Value: tls.CipherSuites,
})
}
if tls.PreferServerCipherSuites != nil {
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
Key: "prefer_server_cipher_suites",
Value: tls.PreferServerCipherSuites,
})
}
if len(tls.CurvePreferences) != 0 {
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
Key: "curve_preferences",
Value: tls.CurvePreferences,
})
}
return append(cfg, yaml.MapItem{Key: "tls_server_config", Value: mtlsServerConfig})
}
func (c Config) addClientTLSConfigToYaml(cfg yaml.MapSlice) yaml.MapSlice {
tls := c.clusterTLSConfig.ClientTLS
mtlsClientConfig := yaml.MapSlice{}
tlsRefs := c.clientTLSReferences
if keyPath := tlsRefs.GetKeyMountPath(); keyPath != "" {
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "key_file", Value: fmt.Sprintf("%s/%s", keyPath, tlsRefs.GetKeyFilename())})
}
if certPath := tlsRefs.GetCertMountPath(); certPath != "" {
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "cert_file", Value: fmt.Sprintf("%s/%s", certPath, tlsRefs.GetCertFilename())})
}
if caPath := tlsRefs.GetCAMountPath(); caPath != "" {
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "ca_file", Value: fmt.Sprintf("%s/%s", caPath, tlsRefs.GetCAFilename())})
}
if serverName := tls.ServerName; serverName != nil {
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "server_name", Value: serverName})
}
if tls.InsecureSkipVerify != nil {
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{
Key: "insecure_skip_verify",
Value: tls.InsecureSkipVerify,
})
}
return append(cfg, yaml.MapItem{Key: "tls_client_config", Value: mtlsClientConfig})
}

View file

@ -0,0 +1,512 @@
// Copyright 2024 The prometheus-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package clustertlsconfig_test
import (
"testing"
"github.com/stretchr/testify/require"
"gotest.tools/v3/golden"
v1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/clustertlsconfig"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
func TestCreateOrUpdateClusterTLSConfigSecret(t *testing.T) {
tc := []struct {
name string
clusterTLSConfig *monitoringv1.ClusterTLSConfig
golden string
}{
{
name: "cluster tls config not defined",
clusterTLSConfig: nil,
golden: "clusterTLS_config_not_defined.golden",
},
{
name: "minimal cluster TLS config with server certificate from secret",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.crt",
},
},
KeySecret: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
InsecureSkipVerify: ptr.To(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.ca",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.crt",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.KeySecret",
},
},
},
golden: "minimal_clusterTLS_config_with_certificate_from_secret.golden",
},
{
name: "minimal cluster TLS config with server and client certificates from configmap",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-configmap",
},
Key: "tls.crt",
},
},
KeySecret: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
InsecureSkipVerify: ptr.To(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "cert.pem",
},
},
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-configmap",
},
Key: "tls.crt",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
},
},
golden: "minimal_clusterTLS_config_with_certificate_from_configmap.golden",
},
{
name: "minimal cluster TLS config with server TLS cert and clientCA from configmap",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-configmap",
},
Key: "tls.crt",
},
},
KeySecret: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
ClientCA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-configmap",
},
Key: "tls.client_ca",
},
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
InsecureSkipVerify: ptr.To(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.ca",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.crt",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
},
},
golden: "minimal_clusterTLS_config_with_client_CA_from_configmap.golden",
},
{
name: "cluster tls config with all parameters from secrets",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
ClientCA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.ca",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.crt",
},
},
KeySecret: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.keySecret",
},
ClientAuthType: ptr.To("RequireAnyClientCert"),
MinVersion: ptr.To("TLS11"),
MaxVersion: ptr.To("TLS13"),
CipherSuites: []string{"cipher-1", "cipher-2"},
PreferServerCipherSuites: ptr.To(false),
CurvePreferences: []string{"curve-1", "curve-2"},
},
ClientTLS: monitoringv1.SafeTLSConfig{
InsecureSkipVerify: ptr.To(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.ca",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.crt",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
},
},
golden: "clusterTLS_config_with_all_parameters_from_secrets.golden",
},
{
name: "cluster tls config with server client CA, cert and key files",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
ClientCAFile: ptr.To("/etc/ssl/certs/tls.client_ca"),
CertFile: ptr.To("/etc/ssl/certs/tls.crt"),
KeyFile: ptr.To("/etc/ssl/secrets/tls.key"),
},
ClientTLS: monitoringv1.SafeTLSConfig{
InsecureSkipVerify: ptr.To(true),
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "cert.pem",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "cert.pem",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "test-secret",
},
Key: "tls.key",
},
},
},
golden: "clusterTLS_config_with_client_CA_cert_and_key_files.golden",
},
}
for _, tt := range tc {
t.Run(tt.name, func(t *testing.T) {
secretName := "test-secret"
config, err := clustertlsconfig.New("/cluster_tls_certs_path_prefix", secretName, tt.clusterTLSConfig)
require.NoError(t, err)
data, err := config.ClusterTLSConfiguration()
require.NoError(t, err)
golden.Assert(t, string(data), tt.golden)
})
}
}
func TestGetMountParameters(t *testing.T) {
ts := []struct {
name string
clusterTLSConfig *monitoringv1.ClusterTLSConfig
expectedVolumes []v1.Volume
expectedMounts []v1.VolumeMount
}{
{
name: "cluster tls config not defined",
clusterTLSConfig: nil,
expectedVolumes: []v1.Volume{
{
Name: "cluster-tls-config",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "cluster-tls-config",
},
},
},
},
expectedMounts: []v1.VolumeMount{
{
Name: "cluster-tls-config",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/cluster-tls-config.yaml",
SubPath: "cluster-tls-config.yaml",
MountPropagation: nil,
SubPathExpr: "",
},
},
},
{
name: "cluster tls config completely defined",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
KeySecret: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "some-secret",
},
Key: "tls.key",
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "some-secret",
},
Key: "tls.crt",
},
},
ClientCA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "some-secret",
},
Key: "tls.client_ca",
},
},
},
ClientTLS: monitoringv1.SafeTLSConfig{
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "some-secret",
},
Key: "tls.key",
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "some-secret",
},
Key: "tls.crt",
},
},
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "some-secret",
},
Key: "tls.client_ca",
},
},
},
},
expectedVolumes: []v1.Volume{
{
Name: "cluster-tls-config",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "cluster-tls-config",
},
},
},
{
Name: "cluster-tls-server-config-secret-key-some-secret-3556f148",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "some-secret",
},
},
},
{
Name: "cluster-tls-server-config-secret-cert-some-secret-3556f148",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "some-secret",
},
},
},
{
Name: "cluster-tls-server-config-secret-client-ca-some-secret-3556f148",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "some-secret",
},
},
},
{
Name: "cluster-tls-client-config-secret-key-some-secret-3556f148",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "some-secret",
},
},
},
{
Name: "cluster-tls-client-config-secret-cert-some-secret-3556f148",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "some-secret",
},
},
},
{
Name: "cluster-tls-client-config-secret-client-ca-some-secret-3556f148",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "some-secret",
},
},
},
},
expectedMounts: []v1.VolumeMount{
{
Name: "cluster-tls-config",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/cluster-tls-config.yaml",
SubPath: "cluster-tls-config.yaml",
MountPropagation: nil,
SubPathExpr: "",
},
{
Name: "cluster-tls-server-config-secret-key-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/server_tls/secret/some-secret-key",
MountPropagation: nil,
SubPathExpr: "",
},
{
Name: "cluster-tls-server-config-secret-cert-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/server_tls/secret/some-secret-cert",
MountPropagation: nil,
SubPathExpr: "",
},
{
Name: "cluster-tls-server-config-secret-client-ca-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/server_tls/secret/some-secret-ca",
MountPropagation: nil,
SubPathExpr: "",
},
{
Name: "cluster-tls-client-config-secret-key-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/client_tls/secret/some-secret-key",
MountPropagation: nil,
SubPathExpr: "",
},
{
Name: "cluster-tls-client-config-secret-cert-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/client_tls/secret/some-secret-cert",
MountPropagation: nil,
SubPathExpr: "",
},
{
Name: "cluster-tls-client-config-secret-client-ca-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/cluster_tls_config/client_tls/secret/some-secret-ca",
MountPropagation: nil,
SubPathExpr: "",
},
},
},
}
for _, tt := range ts {
t.Run(tt.name, func(t *testing.T) {
tlsAssets, err := clustertlsconfig.New("/etc/prometheus/cluster_tls_config", "cluster-tls-config", tt.clusterTLSConfig)
require.NoError(t, err)
_, volumes, mounts, err := tlsAssets.GetMountParameters()
require.NoError(t, err)
require.Equal(t, tt.expectedVolumes, volumes)
require.Equal(t, tt.expectedMounts, mounts)
})
}
}

View file

@ -0,0 +1,19 @@
tls_server_config:
key_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-key/tls.keySecret
cert_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-cert/tls.crt
client_auth_type: RequireAnyClientCert
client_ca_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-ca/tls.ca
min_version: TLS11
max_version: TLS13
cipher_suites:
- cipher-1
- cipher-2
prefer_server_cipher_suites: false
curve_preferences:
- curve-1
- curve-2
tls_client_config:
key_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-cert/tls.crt
ca_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-ca/tls.ca
insecure_skip_verify: true

View file

@ -0,0 +1,9 @@
tls_server_config:
key_file: /etc/ssl/secrets/tls.key
cert_file: /etc/ssl/certs/tls.crt
client_ca_file: /etc/ssl/certs/tls.client_ca
tls_client_config:
key_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-cert/cert.pem
ca_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-ca/cert.pem
insecure_skip_verify: true

View file

@ -0,0 +1,8 @@
tls_server_config:
key_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/server_tls/configmap/test-configmap-cert/tls.crt
tls_client_config:
key_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/client_tls/configmap/test-configmap-cert/tls.crt
ca_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-ca/cert.pem
insecure_skip_verify: true

View file

@ -0,0 +1,8 @@
tls_server_config:
key_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-cert/tls.crt
tls_client_config:
key_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-key/tls.KeySecret
cert_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-cert/tls.crt
ca_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-ca/tls.ca
insecure_skip_verify: true

View file

@ -0,0 +1,9 @@
tls_server_config:
key_file: /cluster_tls_certs_path_prefix/server_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/server_tls/configmap/test-configmap-cert/tls.crt
client_ca_file: /cluster_tls_certs_path_prefix/server_tls/configmap/test-configmap-ca/tls.client_ca
tls_client_config:
key_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-key/tls.key
cert_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-cert/tls.crt
ca_file: /cluster_tls_certs_path_prefix/client_tls/secret/test-secret-ca/tls.ca
insecure_skip_verify: true

View file

@ -40,6 +40,7 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/clustertlsconfig"
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation"
validationv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation/v1alpha1"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@ -562,6 +563,10 @@ func (c *Operator) sync(ctx context.Context, key string) error {
return fmt.Errorf("synchronizing web config secret failed: %w", err)
}
if err := c.createOrUpdateClusterTLSConfigSecret(ctx, am); err != nil {
return fmt.Errorf("synchronizing cluster tls config secret failed: %w", err)
}
svcClient := c.kclient.CoreV1().Services(am.Namespace)
if am.Spec.ServiceName != nil {
selectorLabels := makeSelectorLabels(am.Name)
@ -751,6 +756,7 @@ func createSSetInputHash(a monitoringv1.Alertmanager, c Config, tlsAssets *opera
AlertmanagerAnnotations map[string]string
AlertmanagerGeneration int64
AlertmanagerWebHTTP2 *bool
ALertmanagerClusterTLS string
Config Config
StatefulSetSpec appsv1.StatefulSetSpec
ShardedSecret *operator.ShardedSecret
@ -1689,6 +1695,43 @@ func (c *Operator) createOrUpdateWebConfigSecret(ctx context.Context, a *monitor
return nil
}
func (c *Operator) createOrUpdateClusterTLSConfigSecret(ctx context.Context, a *monitoringv1.Alertmanager) error {
clusterTLSConfig, err := clustertlsconfig.New(
clusterTLSConfigDir,
clusterTLSConfigSecretName(a.Name),
a.Spec.ClusterTLS,
)
if err != nil {
return fmt.Errorf("failed to initialize the configuration: %w", err)
}
data, err := clusterTLSConfig.ClusterTLSConfiguration()
if err != nil {
return fmt.Errorf("failed to generate the configuration: %w", err)
}
s := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: clusterTLSConfig.GetSecretName(),
},
Data: map[string][]byte{
clustertlsconfig.ConfigFileKey: data,
},
}
operator.UpdateObject(
s,
operator.WithLabels(c.config.Labels),
operator.WithAnnotations(c.config.Annotations),
operator.WithManagingOwner(a),
)
if err = k8sutil.CreateOrUpdateSecret(ctx, c.kclient.CoreV1().Secrets(a.Namespace), s); err != nil {
return fmt.Errorf("failed to reconcile secret: %w", err)
}
return nil
}
func logDeprecatedFields(logger *slog.Logger, a *monitoringv1.Alertmanager) {
deprecationWarningf := "field %q is deprecated, field %q should be used instead"

View file

@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/utils/ptr"
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/clustertlsconfig"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/prometheus-operator/prometheus-operator/pkg/k8sutil"
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
@ -49,6 +50,7 @@ const (
alertmanagerTemplatesVolumeName = "notification-templates"
alertmanagerTemplatesDir = "/etc/alertmanager/templates"
webConfigDir = "/etc/alertmanager/web_config"
clusterTLSConfigDir = "/etc/alertmanager/cluster_tls_config"
alertmanagerConfigVolumeName = "config-volume"
alertmanagerConfigDir = "/etc/alertmanager/config"
alertmanagerConfigOutVolumeName = "config-out"
@ -465,6 +467,7 @@ func makeStatefulSetSpec(logger *slog.Logger, a *monitoringv1.Alertmanager, conf
}
var configReloaderWebConfigFile string
watchedDirectories := []string{alertmanagerConfigDir}
configReloaderVolumeMounts := []v1.VolumeMount{
{
@ -624,6 +627,24 @@ func makeStatefulSetSpec(logger *slog.Logger, a *monitoringv1.Alertmanager, conf
configReloaderVolumeMounts = append(configReloaderVolumeMounts, configMount...)
}
if version.GTE(semver.MustParse("0.24.0")) {
clusterTLSConfig, err := clustertlsconfig.New(clusterTLSConfigDir, clusterTLSConfigSecretName(a.Name), a.Spec.ClusterTLS)
if err != nil {
return nil, fmt.Errorf("failed to create cluster TLS configuration: %w", err)
}
confArg, configVol, configMount, err := clusterTLSConfig.GetMountParameters()
if err != nil {
return nil, fmt.Errorf("failed to get mount parameters for cluster TLS configuration: %w", err)
}
if confArg != nil {
amArgs = append(amArgs, fmt.Sprintf("--%s=%s", confArg.Name, confArg.Value))
}
volumes = append(volumes, configVol...)
amVolumeMounts = append(amVolumeMounts, configMount...)
}
finalSelectorLabels := config.Labels.Merge(podSelectorLabels)
finalLabels := config.Labels.Merge(podLabels)
@ -773,6 +794,10 @@ func webConfigSecretName(name string) string {
return fmt.Sprintf("%s-web-config", prefixedName(name))
}
func clusterTLSConfigSecretName(name string) string {
return fmt.Sprintf("%s-cluster-tls-config", prefixedName(name))
}
func volumeName(name string) string {
return fmt.Sprintf("%s-db", prefixedName(name))
}

View file

@ -273,6 +273,11 @@ type AlertmanagerSpec struct {
HostAliases []HostAlias `json:"hostAliases,omitempty"`
// Defines the web command line flags when starting Alertmanager.
Web *AlertmanagerWebSpec `json:"web,omitempty"`
// Configures the mutual TLS configuration for the Alertmanager cluster's gossip protocol.
//
// It requires Alertmanager >= 0.24.0.
//+optional
ClusterTLS *ClusterTLSConfig `json:"clusterTLS,omitempty"`
// alertmanagerConfiguration specifies the configuration of Alertmanager.
//
// If defined, it takes precedence over the `configSecret` field.
@ -512,3 +517,14 @@ type AlertmanagerList struct {
func (l *AlertmanagerList) DeepCopyObject() runtime.Object {
return l.DeepCopy()
}
// ClusterTLSConfig defines the mutual TLS configuration for the Alertmanager cluster TLS protocol.
// +k8s:openapi-gen=true
type ClusterTLSConfig struct {
// Server-side configuration for mutual TLS.
// +required
ServerTLS WebTLSConfig `json:"server"`
// Client-side configuration for mutual TLS.
// +required
ClientTLS SafeTLSConfig `json:"client"`
}

View file

@ -434,6 +434,11 @@ func (in *AlertmanagerSpec) DeepCopyInto(out *AlertmanagerSpec) {
*out = new(AlertmanagerWebSpec)
(*in).DeepCopyInto(*out)
}
if in.ClusterTLS != nil {
in, out := &in.ClusterTLS, &out.ClusterTLS
*out = new(ClusterTLSConfig)
(*in).DeepCopyInto(*out)
}
if in.AlertmanagerConfiguration != nil {
in, out := &in.AlertmanagerConfiguration, &out.AlertmanagerConfiguration
*out = new(AlertmanagerConfiguration)
@ -678,6 +683,23 @@ func (in *BasicAuth) DeepCopy() *BasicAuth {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterTLSConfig) DeepCopyInto(out *ClusterTLSConfig) {
*out = *in
in.ServerTLS.DeepCopyInto(&out.ServerTLS)
in.ClientTLS.DeepCopyInto(&out.ClientTLS)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTLSConfig.
func (in *ClusterTLSConfig) DeepCopy() *ClusterTLSConfig {
if in == nil {
return nil
}
out := new(ClusterTLSConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommonPrometheusFields) DeepCopyInto(out *CommonPrometheusFields) {
*out = *in

View file

@ -76,6 +76,7 @@ type AlertmanagerSpecApplyConfiguration struct {
MinReadySeconds *uint32 `json:"minReadySeconds,omitempty"`
HostAliases []HostAliasApplyConfiguration `json:"hostAliases,omitempty"`
Web *AlertmanagerWebSpecApplyConfiguration `json:"web,omitempty"`
ClusterTLS *ClusterTLSConfigApplyConfiguration `json:"clusterTLS,omitempty"`
AlertmanagerConfiguration *AlertmanagerConfigurationApplyConfiguration `json:"alertmanagerConfiguration,omitempty"`
AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty"`
EnableFeatures []string `json:"enableFeatures,omitempty"`
@ -518,6 +519,14 @@ func (b *AlertmanagerSpecApplyConfiguration) WithWeb(value *AlertmanagerWebSpecA
return b
}
// WithClusterTLS sets the ClusterTLS field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ClusterTLS field is set to the value of the last call.
func (b *AlertmanagerSpecApplyConfiguration) WithClusterTLS(value *ClusterTLSConfigApplyConfiguration) *AlertmanagerSpecApplyConfiguration {
b.ClusterTLS = value
return b
}
// WithAlertmanagerConfiguration sets the AlertmanagerConfiguration field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the AlertmanagerConfiguration field is set to the value of the last call.

View file

@ -0,0 +1,46 @@
// Copyright The prometheus-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1
// ClusterTLSConfigApplyConfiguration represents a declarative configuration of the ClusterTLSConfig type for use
// with apply.
type ClusterTLSConfigApplyConfiguration struct {
ServerTLS *WebTLSConfigApplyConfiguration `json:"server,omitempty"`
ClientTLS *SafeTLSConfigApplyConfiguration `json:"client,omitempty"`
}
// ClusterTLSConfigApplyConfiguration constructs a declarative configuration of the ClusterTLSConfig type for use with
// apply.
func ClusterTLSConfig() *ClusterTLSConfigApplyConfiguration {
return &ClusterTLSConfigApplyConfiguration{}
}
// WithServerTLS sets the ServerTLS field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ServerTLS field is set to the value of the last call.
func (b *ClusterTLSConfigApplyConfiguration) WithServerTLS(value *WebTLSConfigApplyConfiguration) *ClusterTLSConfigApplyConfiguration {
b.ServerTLS = value
return b
}
// WithClientTLS sets the ClientTLS field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ClientTLS field is set to the value of the last call.
func (b *ClusterTLSConfigApplyConfiguration) WithClientTLS(value *SafeTLSConfigApplyConfiguration) *ClusterTLSConfigApplyConfiguration {
b.ClientTLS = value
return b
}

View file

@ -70,6 +70,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
return &monitoringv1.AzureSDKApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("BasicAuth"):
return &monitoringv1.BasicAuthApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("ClusterTLSConfig"):
return &monitoringv1.ClusterTLSConfigApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("CommonPrometheusFields"):
return &monitoringv1.CommonPrometheusFieldsApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("Condition"):

View file

@ -37,6 +37,10 @@ import (
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
)
var (
certsDir = "../../test/e2e/tls_certs/"
)
func newLogger() *slog.Logger {
return slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelWarn}))
}
@ -778,13 +782,13 @@ func TestValidateScrapeIntervalAndTimeout(t *testing.T) {
}
func TestSelectServiceMonitors(t *testing.T) {
ca, err := os.ReadFile("../../test/e2e/remote_write_certs/ca.crt")
ca, err := os.ReadFile(certsDir + "ca.crt")
require.NoError(t, err)
cert, err := os.ReadFile("../../test/e2e/remote_write_certs/client.crt")
cert, err := os.ReadFile(certsDir + "client.crt")
require.NoError(t, err)
key, err := os.ReadFile("../../test/e2e/remote_write_certs/client.key")
key, err := os.ReadFile(certsDir + "client.key")
require.NoError(t, err)
for _, tc := range []struct {
@ -1327,13 +1331,13 @@ func TestSelectPodMonitors(t *testing.T) {
}
func TestSelectScrapeConfigs(t *testing.T) {
ca, err := os.ReadFile("../../test/e2e/remote_write_certs/ca.crt")
ca, err := os.ReadFile(certsDir + "ca.crt")
require.NoError(t, err)
cert, err := os.ReadFile("../../test/e2e/remote_write_certs/client.crt")
cert, err := os.ReadFile(certsDir + "client.crt")
require.NoError(t, err)
key, err := os.ReadFile("../../test/e2e/remote_write_certs/client.key")
key, err := os.ReadFile(certsDir + "client.key")
require.NoError(t, err)
for _, tc := range []struct {
scenario string

View file

@ -78,10 +78,11 @@ func (c Config) GetMountParameters() (monitoringv1.Argument, []v1.Volume, []v1.V
cfgMount := c.makeVolumeMount(destinationPath)
mounts = append(mounts, cfgMount)
tls := c.tlsConfig
if c.tlsConfig != nil {
tlsRefs := newTLSReferences(c.mountingDir, *c.tlsConfig)
tlsVolumes, tlsMounts, err := tlsRefs.getMountParameters()
tlsRefs := NewTLSReferences(c.mountingDir, tls.KeySecret, tls.Cert, tls.ClientCA)
tlsVolumes, tlsMounts, err := tlsRefs.GetMountParameters(volumePrefix)
if err != nil {
return monitoringv1.Argument{}, nil, nil, err
}
@ -130,20 +131,20 @@ func (c Config) addTLSServerConfigToYaml(cfg yaml.MapSlice) yaml.MapSlice {
}
tlsServerConfig := yaml.MapSlice{}
tlsRefs := newTLSReferences(c.mountingDir, *c.tlsConfig)
tlsRefs := NewTLSReferences(c.mountingDir, tls.KeySecret, tls.Cert, tls.ClientCA)
switch {
case ptr.Deref(tls.CertFile, "") != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "cert_file", Value: *tls.CertFile})
case tlsRefs.getCertMountPath() != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "cert_file", Value: filepath.Join(tlsRefs.getCertMountPath(), tlsRefs.getCertFilename())})
case tlsRefs.GetCertMountPath() != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "cert_file", Value: filepath.Join(tlsRefs.GetCertMountPath(), tlsRefs.GetCertFilename())})
}
switch {
case ptr.Deref(tls.KeyFile, "") != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "key_file", Value: *tls.KeyFile})
case tlsRefs.getKeyMountPath() != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "key_file", Value: filepath.Join(tlsRefs.getKeyMountPath(), tlsRefs.getKeyFilename())})
case tlsRefs.GetKeyMountPath() != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "key_file", Value: filepath.Join(tlsRefs.GetKeyMountPath(), tlsRefs.GetKeyFilename())})
}
if ptr.Deref(tls.ClientAuthType, "") != "" {
@ -156,8 +157,8 @@ func (c Config) addTLSServerConfigToYaml(cfg yaml.MapSlice) yaml.MapSlice {
switch {
case ptr.Deref(tls.ClientCAFile, "") != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: *tls.ClientCAFile})
case tlsRefs.getCAMountPath() != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: filepath.Join(tlsRefs.getCAMountPath(), tlsRefs.getCAFilename())})
case tlsRefs.GetCAMountPath() != "":
tlsServerConfig = append(tlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: filepath.Join(tlsRefs.GetCAMountPath(), tlsRefs.GetCAFilename())})
}
if ptr.Deref(tls.MinVersion, "") != "" {

View file

@ -303,7 +303,6 @@ func TestGetMountParameters(t *testing.T) {
Name: "web-config-tls-secret-key-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/web_config/secret/some-secret-key",
SubPath: "",
MountPropagation: nil,
SubPathExpr: "",
},
@ -311,7 +310,6 @@ func TestGetMountParameters(t *testing.T) {
Name: "web-config-tls-secret-cert-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/web_config/secret/some-secret-cert",
SubPath: "",
MountPropagation: nil,
SubPathExpr: "",
},
@ -319,7 +317,6 @@ func TestGetMountParameters(t *testing.T) {
Name: "web-config-tls-secret-client-ca-some-secret-3556f148",
ReadOnly: true,
MountPath: "/etc/prometheus/web_config/secret/some-secret-ca",
SubPath: "",
MountPropagation: nil,
SubPathExpr: "",
},

View file

@ -30,10 +30,9 @@ const (
)
// tlsReferences represent TLS material referenced from secrets/configmaps.
type tlsReferences struct {
// mountPath is the directory where the TLS files are intended to be mounted.
type TLSReferences struct {
// mountPath is the directory where TLS credentials are intended to be mounted.
mountPath string
// keySecret is the Kubernetes Secret containing the TLS private key.
keySecret corev1.SecretKeySelector
// cert is the Kubernetes Secret or ConfigMap containing the TLS certificate.
@ -42,17 +41,17 @@ type tlsReferences struct {
clientCA monitoringv1.SecretOrConfigMap
}
func newTLSReferences(mountPath string, cfg monitoringv1.WebTLSConfig) *tlsReferences {
return &tlsReferences{
func NewTLSReferences(mountPath string, keySecret corev1.SecretKeySelector, cert, clientCA monitoringv1.SecretOrConfigMap) *TLSReferences {
return &TLSReferences{
mountPath: mountPath,
keySecret: cfg.KeySecret,
cert: cfg.Cert,
clientCA: cfg.ClientCA,
keySecret: keySecret,
cert: cert,
clientCA: clientCA,
}
}
// getMountParameters creates volumes and volume mounts referencing the TLS credentials.
func (tr *tlsReferences) getMountParameters() ([]corev1.Volume, []corev1.VolumeMount, error) {
func (tr *TLSReferences) GetMountParameters(volumePrefix string) ([]corev1.Volume, []corev1.VolumeMount, error) {
var (
volumes []corev1.Volume
mounts []corev1.VolumeMount
@ -60,7 +59,7 @@ func (tr *tlsReferences) getMountParameters() ([]corev1.Volume, []corev1.VolumeM
)
prefix := volumePrefix + "secret-key-"
volumes, mounts, err = tr.mountParamsForSecret(volumes, mounts, tr.keySecret, prefix, tr.getKeyMountPath())
volumes, mounts, err = tr.mountParamsForSecret(volumes, mounts, tr.keySecret, prefix, tr.GetKeyMountPath())
if err != nil {
return nil, nil, err
}
@ -68,13 +67,13 @@ func (tr *tlsReferences) getMountParameters() ([]corev1.Volume, []corev1.VolumeM
switch {
case tr.cert.Secret != nil:
prefix := volumePrefix + "secret-cert-"
volumes, mounts, err = tr.mountParamsForSecret(volumes, mounts, *tr.cert.Secret, prefix, tr.getCertMountPath())
volumes, mounts, err = tr.mountParamsForSecret(volumes, mounts, *tr.cert.Secret, prefix, tr.GetCertMountPath())
if err != nil {
return nil, nil, err
}
case tr.cert.ConfigMap != nil:
prefix := volumePrefix + "configmap-cert-"
volumes, mounts, err = tr.mountParamsForConfigmap(volumes, mounts, *tr.cert.ConfigMap, prefix, tr.getCertMountPath())
volumes, mounts, err = tr.mountParamsForConfigmap(volumes, mounts, *tr.cert.ConfigMap, prefix, tr.GetCertMountPath())
if err != nil {
return nil, nil, err
}
@ -83,13 +82,13 @@ func (tr *tlsReferences) getMountParameters() ([]corev1.Volume, []corev1.VolumeM
switch {
case tr.clientCA.Secret != nil:
prefix := volumePrefix + "secret-client-ca-"
volumes, mounts, err = tr.mountParamsForSecret(volumes, mounts, *tr.clientCA.Secret, prefix, tr.getCAMountPath())
volumes, mounts, err = tr.mountParamsForSecret(volumes, mounts, *tr.clientCA.Secret, prefix, tr.GetCAMountPath())
if err != nil {
return nil, nil, err
}
case tr.clientCA.ConfigMap != nil:
prefix := volumePrefix + "configmap-client-ca-"
volumes, mounts, err = tr.mountParamsForConfigmap(volumes, mounts, *tr.clientCA.ConfigMap, prefix, tr.getCAMountPath())
volumes, mounts, err = tr.mountParamsForConfigmap(volumes, mounts, *tr.clientCA.ConfigMap, prefix, tr.GetCAMountPath())
if err != nil {
return nil, nil, err
}
@ -98,7 +97,7 @@ func (tr *tlsReferences) getMountParameters() ([]corev1.Volume, []corev1.VolumeM
return volumes, mounts, nil
}
func (tr *tlsReferences) mountParamsForSecret(
func (tr *TLSReferences) mountParamsForSecret(
volumes []corev1.Volume,
mounts []corev1.VolumeMount,
secret corev1.SecretKeySelector,
@ -137,7 +136,7 @@ func (tr *tlsReferences) mountParamsForSecret(
return volumes, mounts, nil
}
func (tr *tlsReferences) mountParamsForConfigmap(
func (tr *TLSReferences) mountParamsForConfigmap(
volumes []corev1.Volume,
mounts []corev1.VolumeMount,
configMap corev1.ConfigMapKeySelector,
@ -178,19 +177,19 @@ func (tr *tlsReferences) mountParamsForConfigmap(
return volumes, mounts, nil
}
// getKeyMountPath is the mount path of the private key inside a container.
func (tr *tlsReferences) getKeyMountPath() string {
// getKeyMountPath is the mount path of the TLS key inside a prometheus container.
func (tr *TLSReferences) GetKeyMountPath() string {
secret := monitoringv1.SecretOrConfigMap{Secret: &tr.keySecret}
return tr.tlsPathForSelector(secret, "key")
}
// getKeyFilename returns the filename (key) of the private key.
func (tr *tlsReferences) getKeyFilename() string {
// getKeyFilename returns the filename of the private key.
func (tr *TLSReferences) GetKeyFilename() string {
return tr.keySecret.Key
}
// getCertMountPath is the mount path of the TLS certificate inside a container.
func (tr *tlsReferences) getCertMountPath() string {
// getCertMountPath is the mount path of the TLS certificate inside a prometheus container,.
func (tr *TLSReferences) GetCertMountPath() string {
if tr.cert.ConfigMap != nil || tr.cert.Secret != nil {
return tr.tlsPathForSelector(tr.cert, "cert")
}
@ -199,7 +198,7 @@ func (tr *tlsReferences) getCertMountPath() string {
}
// getCertFilename returns the filename (key) of the certificate.
func (tr *tlsReferences) getCertFilename() string {
func (tr *TLSReferences) GetCertFilename() string {
if tr.cert.Secret != nil {
return tr.cert.Secret.Key
} else if tr.cert.ConfigMap != nil {
@ -209,8 +208,8 @@ func (tr *tlsReferences) getCertFilename() string {
return ""
}
// getCAMountPath is the mount path of the client CA certificate inside a container.
func (tr *tlsReferences) getCAMountPath() string {
// getCAMountPath is the mount path of the client CA certificate inside a prometheus container.
func (tr *TLSReferences) GetCAMountPath() string {
if tr.clientCA.ConfigMap != nil || tr.clientCA.Secret != nil {
return tr.tlsPathForSelector(tr.clientCA, "ca")
}
@ -219,7 +218,7 @@ func (tr *tlsReferences) getCAMountPath() string {
}
// getCAFilename retruns the filename (key) of the client CA certificate.
func (tr *tlsReferences) getCAFilename() string {
func (tr *TLSReferences) GetCAFilename() string {
if tr.clientCA.Secret != nil {
return tr.clientCA.Secret.Key
} else if tr.clientCA.ConfigMap != nil {
@ -229,7 +228,7 @@ func (tr *tlsReferences) getCAFilename() string {
return ""
}
func (tr *tlsReferences) tlsPathForSelector(sel monitoringv1.SecretOrConfigMap, mountType string) string {
func (tr *TLSReferences) tlsPathForSelector(sel monitoringv1.SecretOrConfigMap, mountType string) string {
var filename string
if sel.Secret != nil {
filename = filepath.Join("secret", fmt.Sprintf("%s-%s", sel.Secret.Name, mountType))

View file

@ -30,7 +30,7 @@ import (
)
const (
certDirectory = "../test/e2e/remote_write_certs"
certDirectory = "../test/e2e/tls_certs"
validityPeriod = 10 * 365 * 24 * time.Hour
)

View file

@ -374,45 +374,118 @@ func testAMClusterAfterRollingUpdate(t *testing.T) {
}
func testAMClusterGossipSilences(t *testing.T) {
// Don't run Alertmanager tests in parallel. See
// https://github.com/prometheus/alertmanager/issues/1835 for details.
testCtx := framework.NewTestCtx(t)
defer testCtx.Cleanup(t)
ns := framework.CreateNamespace(context.Background(), t, testCtx)
framework.SetupPrometheusRBAC(context.Background(), t, testCtx, ns)
amClusterSize := 3
alertmanager := framework.MakeBasicAlertmanager(ns, "test", int32(amClusterSize))
_, err := framework.CreateAlertmanagerAndWaitUntilReady(context.Background(), alertmanager)
require.NoError(t, err)
for i := 0; i < amClusterSize; i++ {
name := "alertmanager-" + alertmanager.Name + "-" + strconv.Itoa(i)
err := framework.WaitForAlertmanagerPodInitialized(context.Background(), ns, name, amClusterSize, alertmanager.Spec.ForceEnableClusterMode, false)
require.NoError(t, err)
secretName := "cluster-tls-creds"
testcase := []struct {
name string
clusterSize int
clusterTLSConfig *monitoringv1.ClusterTLSConfig
}{
{
name: "alertmanager cluster without mTLS configured",
},
{
name: "alertmanager cluster with mTLS configured",
clusterTLSConfig: &monitoringv1.ClusterTLSConfig{
ServerTLS: monitoringv1.WebTLSConfig{
ClientCA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: "ca.crt",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: "cert.pem",
},
},
KeySecret: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: "key.pem",
},
ClientAuthType: ptr.To("VerifyClientCertIfGiven"),
},
ClientTLS: monitoringv1.SafeTLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: "ca.crt",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: "cert.pem",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: "key.pem",
},
// Since we cannot verify hostname in the cert.
InsecureSkipVerify: ptr.To(true),
},
},
},
}
for _, tc := range testcase {
t.Run(tc.name, func(t *testing.T) {
// Don't run Alertmanager tests in parallel. See
// https://github.com/prometheus/alertmanager/issues/1835 for details.
clusterSize := 3
testCtx := framework.NewTestCtx(t)
defer testCtx.Cleanup(t)
ns := framework.CreateNamespace(context.Background(), t, testCtx)
framework.SetupPrometheusRBAC(context.Background(), t, testCtx, ns)
silID, err := framework.CreateSilence(context.Background(), ns, "alertmanager-test-0")
require.NoError(t, err)
createMutualTLSSecret(t, secretName, ns)
for i := 0; i < amClusterSize; i++ {
err = wait.PollUntilContextTimeout(context.Background(), time.Second, framework.DefaultTimeout, false, func(ctx context.Context) (bool, error) {
silences, err := framework.GetSilences(ctx, ns, "alertmanager-"+alertmanager.Name+"-"+strconv.Itoa(i))
if err != nil {
return false, err
alertmanager := framework.MakeBasicAlertmanager(ns, "test", int32(clusterSize))
alertmanager.Spec.ClusterTLS = tc.clusterTLSConfig
_, err := framework.CreateAlertmanagerAndWaitUntilReady(context.Background(), alertmanager)
require.NoError(t, err)
for i := 0; i < tc.clusterSize; i++ {
name := "alertmanager-" + alertmanager.Name + "-" + strconv.Itoa(i)
err := framework.WaitForAlertmanagerPodInitialized(context.Background(), ns, name, tc.clusterSize, alertmanager.Spec.ForceEnableClusterMode, false)
require.NoError(t, err)
}
if len(silences) != 1 {
return false, nil
}
silID, err := framework.CreateSilence(context.Background(), ns, "alertmanager-test-0")
require.NoError(t, err)
if *silences[0].ID != silID {
return false, fmt.Errorf("expected silence id on alertmanager %v to match id of created silence '%v' but got %v", i, silID, *silences[0].ID)
for i := 0; i < tc.clusterSize; i++ {
err = wait.PollUntilContextTimeout(context.Background(), time.Second, framework.DefaultTimeout, false, func(ctx context.Context) (bool, error) {
silences, err := framework.GetSilences(ctx, ns, "alertmanager-"+alertmanager.Name+"-"+strconv.Itoa(i))
if err != nil {
return false, err
}
if len(silences) != 1 {
return false, nil
}
if *silences[0].ID != silID {
return false, fmt.Errorf("expected silence id on alertmanager %v to match id of created silence '%v' but got %v", i, silID, *silences[0].ID)
}
return true, nil
})
require.NoError(t, err)
}
return true, nil
})
require.NoError(t, err)
}
}

View file

@ -53,7 +53,7 @@ import (
)
var (
certsDir = "../../test/e2e/remote_write_certs/"
certsDir = "../../test/e2e/tls_certs/"
)
func createMutualTLSSecret(t *testing.T, secretName, ns string) {