Skip to content

Commit fcac7e4

Browse files
committed
Implement TLS overlay for Catalogd TLS
Signed-off-by: Tayler Geiger <[email protected]>
1 parent a91c188 commit fcac7e4

38 files changed

+307
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ install.sh
3939
site
4040

4141
.tiltbuild/
42+
.vscode

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ else
5555
$(warning Could not find docker or podman in path! This may result in targets requiring a container runtime failing!)
5656
endif
5757

58-
KUSTOMIZE_BUILD_DIR := config/default
58+
KUSTOMIZE_BUILD_DIR := config/overlays/tls
5959

6060
# Disable -j flag for make
6161
.NOTPARALLEL:
@@ -149,7 +149,7 @@ build-push-e2e-catalog: ## Build the testdata catalog used for e2e tests and pus
149149
# for example: ARTIFACT_PATH=/tmp/artifacts make test-e2e
150150
.PHONY: test-e2e
151151
test-e2e: KIND_CLUSTER_NAME := operator-controller-e2e
152-
test-e2e: KUSTOMIZE_BUILD_DIR := config/e2e
152+
test-e2e: KUSTOMIZE_BUILD_DIR := config/base/e2e
153153
test-e2e: GO_BUILD_FLAGS := -cover
154154
test-e2e: run image-registry build-push-e2e-catalog kind-load-test-artifacts e2e e2e-coverage kind-clean #HELP Run e2e test suite on local kind cluster
155155

Tiltfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repos = cfg.get('repos', ['operator-controller', 'rukpak', 'catalogd'])
99

1010
repo = {
1111
'image': 'quay.io/operator-framework/operator-controller',
12-
'yaml': 'config/default',
12+
'yaml': 'config/overlays/tls',
1313
'binaries': {
1414
'manager': 'operator-controller-controller-manager',
1515
},

cmd/manager/main.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"crypto/tls"
21+
"crypto/x509"
2022
"flag"
2123
"fmt"
24+
"log"
2225
"net/http"
2326
"os"
2427
"time"
@@ -50,9 +53,11 @@ func main() {
5053
probeAddr string
5154
cachePath string
5255
operatorControllerVersion bool
56+
tlsCert string
5357
)
5458
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
5559
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
60+
flag.StringVar(&tlsCert, "tls-cert", "", "The TLS certificate to use for verifying HTTPS connections to the Catalogd web server.")
5661
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
5762
"Enable leader election for controller manager. "+
5863
"Enabling this will ensure there is only one active controller manager.")
@@ -98,8 +103,27 @@ func main() {
98103
os.Exit(1)
99104
}
100105

106+
httpClient := &http.Client{Timeout: 10 * time.Second}
107+
108+
if tlsCert != "" {
109+
cert, err := os.ReadFile(tlsCert)
110+
if err != nil {
111+
log.Fatalf("Failed to read certificate file: %v", err)
112+
}
113+
caCertPool := x509.NewCertPool()
114+
caCertPool.AppendCertsFromPEM(cert)
115+
tlsConfig := &tls.Config{
116+
RootCAs: caCertPool,
117+
MinVersion: tls.VersionTLS12,
118+
}
119+
tlsTransport := &http.Transport{
120+
TLSClientConfig: tlsConfig,
121+
}
122+
httpClient.Transport = tlsTransport
123+
}
124+
101125
cl := mgr.GetClient()
102-
catalogClient := catalogclient.New(cl, cache.NewFilesystemCache(cachePath, &http.Client{Timeout: 10 * time.Second}))
126+
catalogClient := catalogclient.New(cl, cache.NewFilesystemCache(cachePath, httpClient))
103127

104128
if err = (&controllers.ClusterExtensionReconciler{
105129
Client: cl,
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.14.0
7+
name: clusterextensions.olm.operatorframework.io
8+
spec:
9+
group: olm.operatorframework.io
10+
names:
11+
kind: ClusterExtension
12+
listKind: ClusterExtensionList
13+
plural: clusterextensions
14+
singular: clusterextension
15+
scope: Cluster
16+
versions:
17+
- name: v1alpha1
18+
schema:
19+
openAPIV3Schema:
20+
description: ClusterExtension is the Schema for the clusterextensions API
21+
properties:
22+
apiVersion:
23+
description: |-
24+
APIVersion defines the versioned schema of this representation of an object.
25+
Servers should convert recognized schemas to the latest internal value, and
26+
may reject unrecognized values.
27+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
28+
type: string
29+
kind:
30+
description: |-
31+
Kind is a string value representing the REST resource this object represents.
32+
Servers may infer this from the endpoint the client submits requests to.
33+
Cannot be updated.
34+
In CamelCase.
35+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
36+
type: string
37+
metadata:
38+
type: object
39+
spec:
40+
description: ClusterExtensionSpec defines the desired state of ClusterExtension
41+
properties:
42+
channel:
43+
description: Channel constraint definition
44+
maxLength: 48
45+
pattern: ^[a-z0-9]+([\.-][a-z0-9]+)*$
46+
type: string
47+
installNamespace:
48+
description: |-
49+
installNamespace is the namespace where the bundle should be installed. However, note that
50+
the bundle may contain resources that are cluster-scoped or that are
51+
installed in a different namespace. This namespace is expected to exist.
52+
maxLength: 63
53+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
54+
type: string
55+
packageName:
56+
maxLength: 48
57+
pattern: ^[a-z0-9]+(-[a-z0-9]+)*$
58+
type: string
59+
upgradeConstraintPolicy:
60+
default: Enforce
61+
description: Defines the policy for how to handle upgrade constraints
62+
enum:
63+
- Enforce
64+
- Ignore
65+
type: string
66+
version:
67+
description: |-
68+
Version is an optional semver constraint on the package version. If not specified, the latest version available of the package will be installed.
69+
If specified, the specific version of the package will be installed so long as it is available in any of the content sources available.
70+
Examples: 1.2.3, 1.0.0-alpha, 1.0.0-rc.1
71+
72+
73+
For more information on semver, please see https://semver.org/
74+
maxLength: 64
75+
pattern: ^(\s*(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|[x|X|\*])(\.(0|[1-9]\d*|x|X|\*]))?(\.(0|[1-9]\d*|x|X|\*))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)((?:\s+|,\s*|\s*\|\|\s*)(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|x|X|\*])(\.(0|[1-9]\d*|x|X|\*))?(\.(0|[1-9]\d*|x|X|\*]))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)*$
76+
type: string
77+
required:
78+
- installNamespace
79+
- packageName
80+
type: object
81+
status:
82+
description: ClusterExtensionStatus defines the observed state of ClusterExtension
83+
properties:
84+
conditions:
85+
items:
86+
description: "Condition contains details for one aspect of the current
87+
state of this API Resource.\n---\nThis struct is intended for
88+
direct use as an array at the field path .status.conditions. For
89+
example,\n\n\n\ttype FooStatus struct{\n\t // Represents the
90+
observations of a foo's current state.\n\t // Known .status.conditions.type
91+
are: \"Available\", \"Progressing\", and \"Degraded\"\n\t //
92+
+patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t
93+
\ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\"
94+
patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t
95+
\ // other fields\n\t}"
96+
properties:
97+
lastTransitionTime:
98+
description: |-
99+
lastTransitionTime is the last time the condition transitioned from one status to another.
100+
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
101+
format: date-time
102+
type: string
103+
message:
104+
description: |-
105+
message is a human readable message indicating details about the transition.
106+
This may be an empty string.
107+
maxLength: 32768
108+
type: string
109+
observedGeneration:
110+
description: |-
111+
observedGeneration represents the .metadata.generation that the condition was set based upon.
112+
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
113+
with respect to the current state of the instance.
114+
format: int64
115+
minimum: 0
116+
type: integer
117+
reason:
118+
description: |-
119+
reason contains a programmatic identifier indicating the reason for the condition's last transition.
120+
Producers of specific condition types may define expected values and meanings for this field,
121+
and whether the values are considered a guaranteed API.
122+
The value should be a CamelCase string.
123+
This field may not be empty.
124+
maxLength: 1024
125+
minLength: 1
126+
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
127+
type: string
128+
status:
129+
description: status of the condition, one of True, False, Unknown.
130+
enum:
131+
- "True"
132+
- "False"
133+
- Unknown
134+
type: string
135+
type:
136+
description: |-
137+
type of condition in CamelCase or in foo.example.com/CamelCase.
138+
---
139+
Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be
140+
useful (see .node.status.conditions), the ability to deconflict is important.
141+
The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
142+
maxLength: 316
143+
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
144+
type: string
145+
required:
146+
- lastTransitionTime
147+
- message
148+
- reason
149+
- status
150+
- type
151+
type: object
152+
type: array
153+
x-kubernetes-list-map-keys:
154+
- type
155+
x-kubernetes-list-type: map
156+
installedBundle:
157+
properties:
158+
name:
159+
type: string
160+
version:
161+
type: string
162+
required:
163+
- name
164+
- version
165+
type: object
166+
resolvedBundle:
167+
properties:
168+
name:
169+
type: string
170+
version:
171+
type: string
172+
required:
173+
- name
174+
- version
175+
type: object
176+
type: object
177+
type: object
178+
served: true
179+
storage: true
180+
subresources:
181+
status: {}
File renamed without changes.
File renamed without changes.

config/manager/manager.yaml renamed to config/base/manager/manager.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,4 @@ spec:
110110
terminationGracePeriodSeconds: 10
111111
volumes:
112112
- name: cache
113-
emptyDir: {}
113+
emptyDir: {}
File renamed without changes.
File renamed without changes.

config/base/rbac/role.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: manager-role
6+
rules:
7+
- apiGroups:
8+
- catalogd.operatorframework.io
9+
resources:
10+
- catalogmetadata
11+
verbs:
12+
- list
13+
- watch
14+
- apiGroups:
15+
- catalogd.operatorframework.io
16+
resources:
17+
- clustercatalogs
18+
verbs:
19+
- list
20+
- watch
21+
- apiGroups:
22+
- core.rukpak.io
23+
resources:
24+
- bundledeployments
25+
verbs:
26+
- create
27+
- get
28+
- list
29+
- patch
30+
- update
31+
- watch
32+
- apiGroups:
33+
- olm.operatorframework.io
34+
resources:
35+
- clusterextensions
36+
verbs:
37+
- get
38+
- list
39+
- watch
40+
- apiGroups:
41+
- olm.operatorframework.io
42+
resources:
43+
- clusterextensions/finalizers
44+
verbs:
45+
- update
46+
- apiGroups:
47+
- olm.operatorframework.io
48+
resources:
49+
- clusterextensions/status
50+
verbs:
51+
- patch
52+
- update
File renamed without changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Adds namespace to all resources.
2+
namespace: operator-controller-system
3+
4+
# Value of this field is prepended to the
5+
# names of all resources, e.g. a deployment named
6+
# "wordpress" becomes "alices-wordpress".
7+
# Note that it should also match with the prefix (text before '-') of the namespace
8+
# field above.
9+
namePrefix: operator-controller-
10+
11+
# the following config is for teaching kustomize how to do var substitution
12+
apiVersion: kustomize.config.k8s.io/v1beta1
13+
kind: Kustomization
14+
resources:
15+
- ../../base/crd
16+
- ../../base/rbac
17+
- ../../base/manager
18+
19+
patches:
20+
- target:
21+
kind: Deployment
22+
name: controller-manager
23+
path: patches/manager_deployment_cert.yaml
24+
- target:
25+
kind: Namespace
26+
name: system
27+
path: patches/manager_namespace_label.yaml
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
- op: add
2+
path: /spec/template/spec/volumes/-
3+
value: {"name":"ca-certificate", "secret":{"secretName":"catalogd-catalogserver-cert", "optional": false, "items": [{"key": "tls.crt", "path": "tls.crt"}]}}
4+
- op: add
5+
path: /spec/template/spec/containers/0/volumeMounts/-
6+
value: {"name":"ca-certificate", "readOnly": true, "mountPath":"/var/certs"}
7+
- op: add
8+
path: /spec/template/spec/containers/0/args/-
9+
value: "--tls-cert=/var/certs/tls.crt"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- op: add
2+
path: /metadata/labels/trust
3+
value: "enabled"

config/rbac/role.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ rules:
1414
- apiGroups:
1515
- catalogd.operatorframework.io
1616
resources:
17-
- catalogs
17+
- clustercatalogs
1818
verbs:
1919
- list
2020
- watch

config/samples/catalogd_operatorcatalog.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
apiVersion: catalogd.operatorframework.io/v1alpha1
2-
kind: Catalog
2+
kind: ClusterCatalog
33
metadata:
44
name: operatorhubio
55
spec:

internal/controllers/clusterextension_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ type ClusterExtensionReconciler struct {
6565

6666
//+kubebuilder:rbac:groups=core.rukpak.io,resources=bundledeployments,verbs=get;list;watch;create;update;patch
6767

68-
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=catalogs,verbs=list;watch
68+
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=clustercatalogs,verbs=list;watch
6969
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=catalogmetadata,verbs=list;watch
7070

7171
func (r *ClusterExtensionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {

0 commit comments

Comments
 (0)