1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-04-21 03:38:43 +00:00

Enforce TLS secret for the admission webhook ()

The admission webhook service has to deployed with TLS enabled because
the Kubernetes API only supports webhook URLs with a "https://" scheme.

Signed-off-by: Simon Pasquier <spasquie@redhat.com>

Signed-off-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
Simon Pasquier 2022-11-03 10:42:29 +01:00 committed by GitHub
parent d80450032e
commit 2ce4214759
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 35 deletions
example/admission-webhook
jsonnet/prometheus-operator
scripts/generate
test/framework

View file

@ -33,7 +33,11 @@ spec:
topologyKey: kubernetes.io/hostname
automountServiceAccountToken: false
containers:
- image: quay.io/prometheus-operator/admission-webhook:v0.60.1
- args:
- --web.enable-tls=true
- --web.cert-file=/etc/tls/private/tls.crt
- --web.key-file=/etc/tls/private/tls.key
image: quay.io/prometheus-operator/admission-webhook:v0.60.1
name: prometheus-operator-admission-webhook
ports:
- containerPort: 8443
@ -52,7 +56,20 @@ spec:
- ALL
readOnlyRootFilesystem: true
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- mountPath: /etc/tls/private
name: tls-certificates
readOnly: true
securityContext:
runAsNonRoot: true
runAsUser: 65534
serviceAccountName: prometheus-operator-admission-webhook
volumes:
- name: tls-certificates
secret:
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
secretName: admission-webhook-certs

View file

@ -9,7 +9,7 @@ metadata:
spec:
ports:
- name: https
port: 8443
port: 443
targetPort: https
selector:
app.kubernetes.io/name: prometheus-operator-admission-webhook

View file

@ -4,7 +4,13 @@ local defaults = {
namespace: error 'must provide namespace',
version: error 'must provide version',
image: error 'must provide admission webhook image',
port: 8443,
// The name of the Secret containing the TLS certificate and key of the admission webhook service.
tlsSecretName: error 'must provide tlsSecretName',
// The Secret's key containing the TLS certificate.
tlsCertRef: 'tls.crt',
// The Secret's key containing the TLS private key.
tlsPrivateKeyRef: 'tls.key',
port: 443,
replicas: 2,
resources: {
limits: { cpu: '200m', memory: '200Mi' },
@ -54,9 +60,14 @@ function(params) {
name: aw._config.name,
image: aw._config.image,
ports: [{
containerPort: aw._config.port,
containerPort: 8443,
name: 'https',
}],
args: [
'--web.enable-tls=true',
'--web.cert-file=/etc/tls/private/tls.crt',
'--web.key-file=/etc/tls/private/tls.key',
],
resources: aw._config.resources,
terminationMessagePolicy: 'FallbackToLogsOnError',
securityContext: {
@ -64,6 +75,13 @@ function(params) {
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
volumeMounts: [
{
mountPath: '/etc/tls/private',
name: 'tls-certificates',
readOnly: true,
},
],
};
{
apiVersion: 'apps/v1',
@ -87,8 +105,22 @@ function(params) {
},
serviceAccountName: aw._config.name,
automountServiceAccountToken: false,
volumes: [{
name: 'tls-certificates',
secret: {
secretName: aw._config.tlsSecretName,
items: [{
key: aw._config.tlsCertRef,
path: 'tls.crt',
}, {
key: aw._config.tlsPrivateKeyRef,
path: 'tls.key',
}],
},
}],
},
},
} + if aw._config.replicas > 1 then {
// configure hard anti-affinity + rolling update for proper HA.
template+: {

View file

@ -2,6 +2,7 @@ local admissionWebhook = (import 'prometheus-operator/admission-webhook.libsonne
local config = (import 'config.jsonnet');
local aw = admissionWebhook(config {
image: 'quay.io/prometheus-operator/admission-webhook:v' + config.version,
tlsSecretName: 'admission-webhook-certs',
});
{

View file

@ -50,12 +50,13 @@ import (
)
const (
admissionHookSecretName = "prometheus-operator-admission"
standaloneAdmissionHookSecretName = "prometheus-operator-admission-standalone"
prometheusOperatorServiceDeploymentName = "prometheus-operator"
operatorTLSDir = "/etc/tls/private"
prometheusOperatorCertsSecretName = "prometheus-operator-certs"
admissionWebhookServiceName = "prometheus-operator-admission-webhook"
admissionWebhookServiceName = "prometheus-operator-admission-webhook"
standaloneAdmissionHookSecretName = "admission-webhook-certs"
operatorTLSDir = "/etc/tls/private"
)
type Framework struct {
@ -240,15 +241,6 @@ func (f *Framework) CreateOrUpdatePrometheusOperator(ctx context.Context, ns str
}
}
certBytes, keyBytes, err := certutil.GenerateSelfSignedCertKey(fmt.Sprintf("%s.%s.svc", prometheusOperatorServiceDeploymentName, ns), nil, nil)
if err != nil {
return nil, errors.Wrap(err, "failed to generate certificate and key")
}
if err := f.CreateOrUpdateSecretWithCert(ctx, certBytes, keyBytes, ns, admissionHookSecretName); err != nil {
return nil, errors.Wrap(err, "failed to create or update admission webhook secret")
}
err = f.CreateOrUpdateCRDAndWaitUntilReady(ctx, monitoringv1.AlertmanagerName, func(opts metav1.ListOptions) (runtime.Object, error) {
return f.MonClientV1.Alertmanagers(v1.NamespaceAll).List(ctx, opts)
})
@ -312,6 +304,15 @@ func (f *Framework) CreateOrUpdatePrometheusOperator(ctx context.Context, ns str
return nil, errors.Wrap(err, "wait for AlertmanagerConfig v1beta1 CRD")
}
certBytes, keyBytes, err := certutil.GenerateSelfSignedCertKey(fmt.Sprintf("%s.%s.svc", prometheusOperatorServiceDeploymentName, ns), nil, nil)
if err != nil {
return nil, errors.Wrap(err, "failed to generate certificate and key")
}
if err := f.CreateOrUpdateSecretWithCert(ctx, certBytes, keyBytes, ns, prometheusOperatorCertsSecretName); err != nil {
return nil, errors.Wrap(err, "failed to create or update prometheus-operator TLS secret")
}
deploy, err := MakeDeployment(fmt.Sprintf("%s/rbac/prometheus-operator/prometheus-operator-deployment.yaml", f.exampleDir))
if err != nil {
return nil, err
@ -380,7 +381,7 @@ func (f *Framework) CreateOrUpdatePrometheusOperator(ctx context.Context, ns str
deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes,
v1.Volume{
Name: "cert",
VolumeSource: v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: admissionHookSecretName}}})
VolumeSource: v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: prometheusOperatorCertsSecretName}}})
deploy.Spec.Template.Spec.Containers[0].VolumeMounts = append(deploy.Spec.Template.Spec.Containers[0].VolumeMounts,
v1.VolumeMount{Name: "cert", MountPath: operatorTLSDir, ReadOnly: true})
@ -421,25 +422,25 @@ func (f *Framework) CreateOrUpdatePrometheusOperator(ctx context.Context, ns str
finalizer, err := f.createOrUpdateMutatingHook(ctx, b, ns, fmt.Sprintf("%s/prometheus-operator-mutatingwebhook.yaml", f.resourcesDir))
if err != nil {
return nil, errors.Wrap(err, "failed to create or update mutating webhook")
return nil, errors.Wrap(err, "failed to create or update mutating webhook for PrometheusRule objects")
}
finalizers = append(finalizers, finalizer)
finalizer, err = f.createOrUpdateValidatingHook(ctx, b, ns, fmt.Sprintf("%s/prometheus-operator-validatingwebhook.yaml", f.resourcesDir))
if err != nil {
return nil, errors.Wrap(err, "failed to create or update validating webhook")
return nil, errors.Wrap(err, "failed to create or update validating webhook for PrometheusRule objects")
}
finalizers = append(finalizers, finalizer)
finalizer, err = f.createOrUpdateValidatingHook(ctx, b, ns, fmt.Sprintf("%s/alertmanager-config-validating-webhook.yaml", f.resourcesDir))
if err != nil {
return nil, errors.Wrap(err, "failed to create or update validating webhook for AlertManagerConfigs")
return nil, errors.Wrap(err, "failed to create or update validating webhook for AlertManagerConfig objects")
}
finalizers = append(finalizers, finalizer)
finalizer, err = f.configureAlertmanagerConfigConversion(ctx, webhookService, b)
if err != nil {
return nil, errors.Wrap(err, "failed to configure conversion webhook for AlertManagerConfigs")
return nil, errors.Wrap(err, "failed to configure conversion webhook for AlertManagerConfig objects")
}
finalizers = append(finalizers, finalizer)
}
@ -664,9 +665,11 @@ func (f *Framework) configureAlertmanagerConfigConversion(ctx context.Context, s
return finalizerFn, nil
}
// CreateAdmissionWebhookServer deploys an HTTPS server
// Acts as a validating and mutating webhook server for PrometheusRule and AlertManagerConfig
// Returns the CA, which can be used to access the server over TLS
// CreateOrUpdateAdmissionWebhookServer deploys an HTTPS server which acts as a
// validating and mutating webhook server for PrometheusRule and
// AlertManagerConfig. It is also able to convert AlertmanagerConfig objects
// from v1alpha1 to v1beta1.
// Returns the service and the certificate authority which can be used to trust the TLS certificate of the server.
func (f *Framework) CreateOrUpdateAdmissionWebhookServer(
ctx context.Context,
namespace string,
@ -691,7 +694,8 @@ func (f *Framework) CreateOrUpdateAdmissionWebhookServer(
return nil, nil, err
}
// Only 1 replica needed for the tests.
// Deploy only 1 replica because the end-to-end environment (single node
// cluster) can't satisfy the anti-affinity rules.
deploy.Spec.Replicas = func(i int32) *int32 { return &i }(1)
deploy.Spec.Template.Spec.Affinity = nil
deploy.Spec.Strategy = appsv1.DeploymentStrategy{}
@ -711,14 +715,12 @@ func (f *Framework) CreateOrUpdateAdmissionWebhookServer(
}
}
// Load the certificate and key from the created secret into the server
deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes,
v1.Volume{
Name: "cert",
VolumeSource: v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: standaloneAdmissionHookSecretName}}})
deploy.Spec.Template.Spec.Containers[0].VolumeMounts = append(deploy.Spec.Template.Spec.Containers[0].VolumeMounts,
v1.VolumeMount{Name: "cert", MountPath: operatorTLSDir, ReadOnly: true})
// TODO(simonpasquier): remove after v0.61
deploy.Spec.Template.Spec.Volumes = []v1.Volume{{
Name: "cert",
VolumeSource: v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: standaloneAdmissionHookSecretName}}}}
// TODO(simonpasquier): remove after v0.61
deploy.Spec.Template.Spec.Containers[0].VolumeMounts = []v1.VolumeMount{{Name: "cert", MountPath: operatorTLSDir, ReadOnly: true}}
_, err = f.createOrUpdateServiceAccount(ctx, namespace, fmt.Sprintf("%s/admission-webhook/service-account.yaml", f.exampleDir))
if err != nil {
@ -736,6 +738,7 @@ func (f *Framework) CreateOrUpdateAdmissionWebhookServer(
}
service.Namespace = namespace
// TODO(simonpasquier): remove after v0.61
service.Spec.Ports = []v1.ServicePort{{Name: "https", Port: 443, TargetPort: intstr.FromInt(8443)}}
if _, err := f.CreateOrUpdateServiceAndWaitUntilReady(ctx, namespace, service); err != nil {

View file

@ -8,7 +8,6 @@ webhooks:
name: prometheus-operator-admission-webhook
namespace: default
path: /admission-prometheusrules/mutate
failurePolicy: Fail
name: prometheusrulemutate.monitoring.coreos.com
namespaceSelector: {}