Skip to content

Commit 28e765b

Browse files
committed
CM-716: Add HTTP01 Challenge Proxy controller
Add the HTTP01 Challenge Proxy feature to cert-manager-operator, enabling cert-manager to complete HTTP01 ACME challenges for the API endpoint on baremetal platforms where the API VIP is not exposed via OpenShift Ingress. This follows the IstioCSR/TrustManager controller pattern and includes: - HTTP01Proxy CRD with mode (DefaultDeployment/CustomDeployment) and optional customDeployment.internalPort configuration - Full controller-runtime reconciler with finalizer handling, status conditions (Ready/Degraded), and managed resource watches - Platform validation via Infrastructure CR — only deploys on BareMetal platforms with distinct API/Ingress VIPs, sets Degraded condition with descriptive message on unsupported platforms - DaemonSet deployment on control plane nodes with hostNetwork, nftables NET_ADMIN capability, and privileged SCC - RBAC for reading cluster config and managing MachineConfig resources - NetworkPolicies for deny-all and allow-egress - FeatureHTTP01Proxy feature gate (Alpha, default: false) - Integrated with unified cache builder and common package utilities - Controller-runtime metrics on :8085 to avoid library-go port conflict - Generated clientset, informers, listers, and apply configurations Ref: openshift/enhancements#1929
1 parent 2beb5f9 commit 28e765b

44 files changed

Lines changed: 2446 additions & 8 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,12 @@ local-run: build ## Run the operator locally against the cluster configured in ~
322322
RELATED_IMAGE_CERT_MANAGER_ACMESOLVER=quay.io/jetstack/cert-manager-acmesolver:$(CERT_MANAGER_VERSION) \
323323
RELATED_IMAGE_CERT_MANAGER_ISTIOCSR=quay.io/jetstack/cert-manager-istio-csr:$(ISTIO_CSR_VERSION) \
324324
RELATED_IMAGE_CERT_MANAGER_TRUST_MANAGER=quay.io/jetstack/trust-manager:$(TRUST_MANAGER_VERSION) \
325+
RELATED_IMAGE_CERT_MANAGER_HTTP01PROXY=quay.io/bapalm/cert-mgr-http01-proxy:latest \
325326
OPERATOR_NAME=cert-manager-operator \
326327
OPERAND_IMAGE_VERSION=$(BUNDLE_VERSION) \
327328
ISTIOCSR_OPERAND_IMAGE_VERSION=$(ISTIO_CSR_VERSION) \
328329
TRUSTMANAGER_OPERAND_IMAGE_VERSION=$(TRUST_MANAGER_VERSION) \
330+
HTTP01PROXY_OPERAND_IMAGE_VERSION=0.1.0 \
329331
OPERATOR_IMAGE_VERSION=$(BUNDLE_VERSION) \
330332
./cert-manager-operator start \
331333
--config=./hack/local-run-config.yaml \

api/operator/v1alpha1/features.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,19 @@ var (
2121
// For more details,
2222
// https://github.com/openshift/enhancements/blob/master/enhancements/cert-manager/trust-manager-controller.md
2323
FeatureTrustManager featuregate.Feature = "TrustManager"
24+
25+
// HTTP01Proxy enables the controller for http01proxies.operator.openshift.io resource,
26+
// which extends cert-manager-operator to deploy and manage the HTTP01 challenge proxy.
27+
// The proxy enables cert-manager to complete HTTP01 ACME challenges for the API endpoint
28+
// on baremetal platforms where the API VIP is not exposed via OpenShift Ingress.
29+
//
30+
// For more details,
31+
// https://github.com/openshift/enhancements/pull/1929
32+
FeatureHTTP01Proxy featuregate.Feature = "HTTP01Proxy"
2433
)
2534

2635
var OperatorFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
2736
FeatureIstioCSR: {Default: true, PreRelease: featuregate.GA},
2837
FeatureTrustManager: {Default: false, PreRelease: "TechPreview"},
38+
FeatureHTTP01Proxy: {Default: false, PreRelease: featuregate.Alpha},
2939
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
func init() {
8+
SchemeBuilder.Register(&HTTP01Proxy{}, &HTTP01ProxyList{})
9+
}
10+
11+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
12+
// +kubebuilder:object:root=true
13+
14+
// HTTP01ProxyList is a list of HTTP01Proxy objects.
15+
type HTTP01ProxyList struct {
16+
metav1.TypeMeta `json:",inline"`
17+
18+
// metadata is the standard list's metadata.
19+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
20+
metav1.ListMeta `json:"metadata"`
21+
Items []HTTP01Proxy `json:"items"`
22+
}
23+
24+
// +genclient
25+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
26+
// +kubebuilder:object:root=true
27+
// +kubebuilder:subresource:status
28+
// +kubebuilder:resource:path=http01proxies,scope=Namespaced,categories={cert-manager-operator},shortName=http01proxy
29+
// +kubebuilder:printcolumn:name="Mode",type="string",JSONPath=".spec.mode"
30+
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status"
31+
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message"
32+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
33+
// +kubebuilder:metadata:labels={"app.kubernetes.io/name=http01proxy", "app.kubernetes.io/part-of=cert-manager-operator"}
34+
35+
// HTTP01Proxy describes the configuration for the HTTP01 challenge proxy
36+
// that redirects traffic from the API endpoint on port 80 to ingress routers.
37+
// This enables cert-manager to perform HTTP01 ACME challenges for API endpoint certificates.
38+
// The name must be `default` to make HTTP01Proxy a singleton.
39+
//
40+
// When an HTTP01Proxy is created, the proxy DaemonSet is deployed on control plane nodes.
41+
//
42+
// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'default'",message="http01proxy is a singleton, .metadata.name must be 'default'"
43+
// +operator-sdk:csv:customresourcedefinitions:displayName="HTTP01Proxy"
44+
type HTTP01Proxy struct {
45+
metav1.TypeMeta `json:",inline"`
46+
47+
// metadata is the standard object's metadata.
48+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
49+
metav1.ObjectMeta `json:"metadata,omitempty"`
50+
51+
// spec is the specification of the desired behavior of the HTTP01Proxy.
52+
// +kubebuilder:validation:Required
53+
// +required
54+
Spec HTTP01ProxySpec `json:"spec"`
55+
56+
// status is the most recently observed status of the HTTP01Proxy.
57+
// +kubebuilder:validation:Optional
58+
// +optional
59+
Status HTTP01ProxyStatus `json:"status,omitempty"`
60+
}
61+
62+
// HTTP01ProxyMode controls how the HTTP01 challenge proxy is deployed.
63+
// +kubebuilder:validation:Enum=DefaultDeployment;CustomDeployment
64+
type HTTP01ProxyMode string
65+
66+
const (
67+
// HTTP01ProxyModeDefault enables the proxy with default configuration.
68+
HTTP01ProxyModeDefault HTTP01ProxyMode = "DefaultDeployment"
69+
70+
// HTTP01ProxyModeCustom enables the proxy with user-specified configuration.
71+
HTTP01ProxyModeCustom HTTP01ProxyMode = "CustomDeployment"
72+
)
73+
74+
// HTTP01ProxySpec is the specification of the desired behavior of the HTTP01Proxy.
75+
// +kubebuilder:validation:XValidation:rule="self.mode == 'CustomDeployment' ? has(self.customDeployment) : !has(self.customDeployment)",message="customDeployment is required when mode is CustomDeployment and forbidden otherwise"
76+
type HTTP01ProxySpec struct {
77+
// mode controls whether the HTTP01 challenge proxy is active and how it should be deployed.
78+
// DefaultDeployment enables the proxy with default configuration.
79+
// CustomDeployment enables the proxy with user-specified configuration.
80+
// +kubebuilder:validation:Required
81+
// +required
82+
Mode HTTP01ProxyMode `json:"mode"`
83+
84+
// customDeployment contains configuration options when mode is CustomDeployment.
85+
// This field is only valid when mode is CustomDeployment.
86+
// +kubebuilder:validation:Optional
87+
// +optional
88+
CustomDeployment *HTTP01ProxyCustomDeploymentSpec `json:"customDeployment,omitempty"`
89+
}
90+
91+
// HTTP01ProxyCustomDeploymentSpec contains configuration for custom proxy deployment.
92+
type HTTP01ProxyCustomDeploymentSpec struct {
93+
// internalPort specifies the internal port used by the proxy service.
94+
// Valid values are 1024-65535.
95+
// +kubebuilder:validation:Minimum=1024
96+
// +kubebuilder:validation:Maximum=65535
97+
// +kubebuilder:default=8888
98+
// +optional
99+
InternalPort int32 `json:"internalPort,omitempty"`
100+
}
101+
102+
// HTTP01ProxyStatus is the most recently observed status of the HTTP01Proxy.
103+
type HTTP01ProxyStatus struct {
104+
// conditions holds information about the current state of the HTTP01 proxy deployment.
105+
ConditionalStatus `json:",inline,omitempty"`
106+
107+
// proxyImage is the name of the image and the tag used for deploying the proxy.
108+
ProxyImage string `json:"proxyImage,omitempty"`
109+
}

api/operator/v1alpha1/zz_generated.deepcopy.go

Lines changed: 110 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRole
3+
metadata:
4+
name: cert-manager-http01-proxy
5+
labels:
6+
app: cert-manager-http01-proxy
7+
app.kubernetes.io/name: cert-manager-http01-proxy
8+
app.kubernetes.io/part-of: cert-manager-operator
9+
rules:
10+
- apiGroups:
11+
- config.openshift.io
12+
resources:
13+
- clusterversions
14+
- infrastructures
15+
- ingresses
16+
verbs:
17+
- get
18+
- list
19+
- watch
20+
- apiGroups:
21+
- operator.openshift.io
22+
resources:
23+
- machineconfigurations
24+
verbs:
25+
- update
26+
- apiGroups:
27+
- machineconfiguration.openshift.io
28+
resources:
29+
- machineconfigs
30+
verbs:
31+
- get
32+
- list
33+
- create
34+
- update
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRoleBinding
3+
metadata:
4+
name: cert-manager-http01-proxy
5+
labels:
6+
app: cert-manager-http01-proxy
7+
app.kubernetes.io/name: cert-manager-http01-proxy
8+
app.kubernetes.io/part-of: cert-manager-operator
9+
roleRef:
10+
apiGroup: rbac.authorization.k8s.io
11+
kind: ClusterRole
12+
name: cert-manager-http01-proxy
13+
subjects:
14+
- kind: ServiceAccount
15+
name: cert-manager-http01-proxy
16+
namespace: cert-manager-operator
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
apiVersion: apps/v1
2+
kind: DaemonSet
3+
metadata:
4+
name: cert-manager-http01-proxy
5+
namespace: cert-manager-operator
6+
labels:
7+
app: cert-manager-http01-proxy
8+
app.kubernetes.io/name: cert-manager-http01-proxy
9+
app.kubernetes.io/part-of: cert-manager-operator
10+
spec:
11+
selector:
12+
matchLabels:
13+
app: cert-manager-http01-proxy
14+
updateStrategy:
15+
type: RollingUpdate
16+
template:
17+
metadata:
18+
labels:
19+
app: cert-manager-http01-proxy
20+
app.kubernetes.io/name: cert-manager-http01-proxy
21+
app.kubernetes.io/part-of: cert-manager-operator
22+
spec:
23+
serviceAccountName: cert-manager-http01-proxy
24+
hostNetwork: true
25+
nodeSelector:
26+
node-role.kubernetes.io/master: ""
27+
tolerations:
28+
- key: node-role.kubernetes.io/master
29+
operator: Exists
30+
effect: NoSchedule
31+
- key: node-role.kubernetes.io/control-plane
32+
operator: Exists
33+
effect: NoSchedule
34+
containers:
35+
- name: http01-proxy
36+
image: ${RELATED_IMAGE_CERT_MANAGER_HTTP01PROXY}
37+
ports:
38+
- name: proxy
39+
containerPort: 8888
40+
hostPort: 8888
41+
protocol: TCP
42+
env:
43+
- name: PROXY_PORT
44+
value: "8888"
45+
securityContext:
46+
capabilities:
47+
add:
48+
- NET_ADMIN
49+
drop:
50+
- ALL
51+
runAsNonRoot: false
52+
resources:
53+
requests:
54+
cpu: 10m
55+
memory: 32Mi
56+
limits:
57+
cpu: 100m
58+
memory: 64Mi
59+
priorityClassName: system-cluster-critical
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRoleBinding
3+
metadata:
4+
name: cert-manager-http01-proxy-scc
5+
labels:
6+
app: cert-manager-http01-proxy
7+
app.kubernetes.io/name: cert-manager-http01-proxy
8+
app.kubernetes.io/part-of: cert-manager-operator
9+
roleRef:
10+
apiGroup: rbac.authorization.k8s.io
11+
kind: ClusterRole
12+
name: system:openshift:scc:privileged
13+
subjects:
14+
- kind: ServiceAccount
15+
name: cert-manager-http01-proxy
16+
namespace: cert-manager-operator
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: v1
2+
kind: ServiceAccount
3+
metadata:
4+
name: cert-manager-http01-proxy
5+
namespace: cert-manager-operator
6+
labels:
7+
app: cert-manager-http01-proxy
8+
app.kubernetes.io/name: cert-manager-http01-proxy
9+
app.kubernetes.io/part-of: cert-manager-operator

0 commit comments

Comments
 (0)