diff --git a/chart/templates/proxy_injector-rbac.yaml b/chart/templates/proxy_injector-rbac.yaml index daa17636b..16e893aa6 100644 --- a/chart/templates/proxy_injector-rbac.yaml +++ b/chart/templates/proxy_injector-rbac.yaml @@ -41,4 +41,36 @@ apiVersion: v1 metadata: name: linkerd-proxy-injector namespace: {{.Namespace}} +--- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: {{ .Namespace }} + labels: + {{ .ControllerComponentLabel }}: proxy-injector + annotations: + {{ .CreatedByAnnotation }}: {{ .CliVersion }} +type: Opaque +data: + crt.pem: {{ b64enc .ProxyInjector.CrtPEM }} + key.pem: {{ b64enc .ProxyInjector.KeyPEM }} +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: {{ .Namespace }} + path: "/" + caBundle: {{ b64enc .ProxyInjector.CrtPEM }} + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] {{end -}} diff --git a/chart/templates/proxy_injector.yaml b/chart/templates/proxy_injector.yaml index 351a871c3..8abc7ac75 100644 --- a/chart/templates/proxy_injector.yaml +++ b/chart/templates/proxy_injector.yaml @@ -32,7 +32,6 @@ spec: imagePullPolicy: {{.ImagePullPolicy}} args: - "proxy-injector" - - "-controller-namespace={{.Namespace}}" - "-log-level={{.ControllerLogLevel}}" ports: - name: proxy-injector @@ -40,6 +39,9 @@ spec: volumeMounts: - name: config mountPath: /var/run/linkerd/config + - name: tls + mountPath: /var/run/linkerd/tls + readOnly: true livenessProbe: httpGet: path: /ping @@ -59,6 +61,9 @@ spec: - name: config configMap: name: linkerd-config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls --- kind: Service apiVersion: v1 diff --git a/chart/templates/sp_validator-rbac.yaml b/chart/templates/sp_validator-rbac.yaml index 93ef1d9e6..55a195292 100644 --- a/chart/templates/sp_validator-rbac.yaml +++ b/chart/templates/sp_validator-rbac.yaml @@ -35,4 +35,36 @@ apiVersion: v1 metadata: name: linkerd-sp-validator namespace: {{.Namespace}} +--- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: {{ .Namespace }} + labels: + {{ .ControllerComponentLabel }}: sp-validator + annotations: + {{ .CreatedByAnnotation }}: {{ .CliVersion }} +type: Opaque +data: + crt.pem: {{ b64enc .ProfileValidator.CrtPEM }} + key.pem: {{ b64enc .ProfileValidator.KeyPEM }} +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: {{ .Namespace }} + path: "/" + caBundle: {{ b64enc .ProfileValidator.CrtPEM }} + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] {{end -}} diff --git a/chart/templates/sp_validator.yaml b/chart/templates/sp_validator.yaml index 88b526a27..4e7989b56 100644 --- a/chart/templates/sp_validator.yaml +++ b/chart/templates/sp_validator.yaml @@ -50,11 +50,14 @@ spec: imagePullPolicy: {{.ImagePullPolicy}} args: - "sp-validator" - - "-controller-namespace={{.Namespace}}" - "-log-level={{.ControllerLogLevel}}" ports: - name: sp-validator containerPort: 8443 + volumeMounts: + - name: tls + mountPath: /var/run/linkerd/tls + readOnly: true livenessProbe: httpGet: path: /ping @@ -71,7 +74,7 @@ spec: securityContext: runAsUser: {{.ControllerUID}} volumes: - - name: config - configMap: - name: linkerd-config + - name: tls + secret: + secretName: linkerd-sp-validator-tls {{end -}} diff --git a/cli/cmd/install.go b/cli/cmd/install.go index 9750194fa..66904327e 100644 --- a/cli/cmd/install.go +++ b/cli/cmd/install.go @@ -68,7 +68,9 @@ type ( TapResources, WebResources *resources - Identity *installIdentityValues + Identity *installIdentityValues + ProxyInjector *proxyInjectorValues + ProfileValidator *profileValidatorValues } configJSONs struct{ Global, Proxy, Install string } @@ -96,6 +98,18 @@ type ( CrtExpiryAnnotation string } + proxyInjectorValues struct { + *tlsValues + } + + profileValidatorValues struct { + *tlsValues + } + + tlsValues struct { + KeyPEM, CrtPEM string + } + // installOptions holds values for command line flags that apply to the install // command. All fields in this struct should have corresponding flags added in // the newCmdInstall func later in this file. It also embeds proxyConfigOptions @@ -115,8 +129,9 @@ type ( recordedFlags []*pb.Install_Flag - // A function pointer that can be overridden for tests - generateUUID func() string + // function pointers that can be overridden for tests + generateUUID func() string + generateWebhookTLS func(webhook string) (*tlsValues, error) } installIdentityOptions struct { @@ -188,6 +203,18 @@ func newInstallOptionsWithDefaults() *installOptions { } return id.String() }, + + generateWebhookTLS: func(webhook string) (*tlsValues, error) { + root, err := tls.GenerateRootCAWithDefaults(webhookCommonName(webhook)) + if err != nil { + return nil, fmt.Errorf("failed to generate root certificate for control plane CA: %s", err) + } + + return &tlsValues{ + KeyPEM: root.Cred.EncodePrivateKeyPEM(), + CrtPEM: root.Cred.Crt.EncodeCertificatePEM(), + }, nil + }, } } @@ -338,6 +365,19 @@ func (options *installOptions) validateAndBuild(stage string, flags *pflag.FlagS return nil, nil, err } values.Identity = identityValues + + proxyInjectorTLS, err := options.generateWebhookTLS(k8s.ProxyInjectorWebhookServiceName) + if err != nil { + return nil, nil, err + } + values.ProxyInjector = &proxyInjectorValues{proxyInjectorTLS} + + profileValidatorTLS, err := options.generateWebhookTLS(k8s.SPValidatorWebhookServiceName) + if err != nil { + return nil, nil, err + } + values.ProfileValidator = &profileValidatorValues{profileValidatorTLS} + values.stage = stage return values, configs, nil @@ -963,3 +1003,24 @@ func (idvals *installIdentityValues) toIdentityContext() *pb.IdentityContext { ClockSkewAllowance: ptypes.DurationProto(csa), } } + +func webhookCommonName(webhook string) string { + return fmt.Sprintf("%s.%s.svc", webhook, controlPlaneNamespace) +} + +func webhookSecretName(webhook string) string { + return fmt.Sprintf("%s-tls", webhook) +} + +func verifyWebhookTLS(value *tlsValues, webhook string) error { + crt, err := tls.DecodePEMCrt(value.CrtPEM) + if err != nil { + return err + } + roots := crt.CertPool() + if err := crt.Verify(roots, webhookCommonName(webhook)); err != nil { + return err + } + + return nil +} diff --git a/cli/cmd/install_test.go b/cli/cmd/install_test.go index 7f52a384b..b1db9db17 100644 --- a/cli/cmd/install_test.go +++ b/cli/cmd/install_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/linkerd/linkerd2/controller/gen/config" + "github.com/linkerd/linkerd2/pkg/k8s" ) func TestRender(t *testing.T) { @@ -57,6 +58,18 @@ func TestRender(t *testing.T) { }, ControllerReplicas: 1, Identity: defaultValues.Identity, + ProxyInjector: &proxyInjectorValues{ + &tlsValues{ + KeyPEM: "proxy injector key", + CrtPEM: "proxy injector crt", + }, + }, + ProfileValidator: &profileValidatorValues{ + &tlsValues{ + KeyPEM: "profile validator key", + CrtPEM: "profile validator crt", + }, + }, } haOptions := testInstallOptions() @@ -118,6 +131,7 @@ func testInstallOptions() *installOptions { o.generateUUID = func() string { return "deaab91a-f4ab-448a-b7d1-c832a2fa0a60" } + o.generateWebhookTLS = fakeGenerateWebhookTLS o.identityOptions.crtPEMFile = filepath.Join("testdata", "crt.pem") o.identityOptions.keyPEMFile = filepath.Join("testdata", "key.pem") o.identityOptions.trustPEMFile = filepath.Join("testdata", "trust-anchors.pem") @@ -182,3 +196,19 @@ func TestValidate(t *testing.T) { } }) } + +func fakeGenerateWebhookTLS(webhook string) (*tlsValues, error) { + switch webhook { + case k8s.ProxyInjectorWebhookServiceName: + return &tlsValues{ + KeyPEM: "proxy injector key", + CrtPEM: "proxy injector crt", + }, nil + case k8s.SPValidatorWebhookServiceName: + return &tlsValues{ + KeyPEM: "profile validator key", + CrtPEM: "profile validator crt", + }, nil + } + return nil, nil +} diff --git a/cli/cmd/testdata/install_config.golden b/cli/cmd/testdata/install_config.golden index dde24697f..5fae9dbbd 100644 --- a/cli/cmd/testdata/install_config.golden +++ b/cli/cmd/testdata/install_config.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: proxy-injector + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: linkerd + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: sp-validator + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: linkerd + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### diff --git a/cli/cmd/testdata/install_control-plane.golden b/cli/cmd/testdata/install_control-plane.golden index 884c9cd4b..62c9dfdf4 100644 --- a/cli/cmd/testdata/install_control-plane.golden +++ b/cli/cmd/testdata/install_control-plane.golden @@ -1273,7 +1273,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1297,6 +1296,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1414,6 +1416,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity @@ -1490,7 +1495,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1511,6 +1515,10 @@ spec: resources: {} securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1625,9 +1633,9 @@ spec: terminationMessagePolicy: FallbackToLogsOnError serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity diff --git a/cli/cmd/testdata/install_default.golden b/cli/cmd/testdata/install_default.golden index 37e7e1690..cc65c2c5c 100644 --- a/cli/cmd/testdata/install_default.golden +++ b/cli/cmd/testdata/install_default.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: proxy-injector + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: linkerd + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: sp-validator + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: linkerd + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### @@ -1630,7 +1694,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1654,6 +1717,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1771,6 +1837,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity @@ -1847,7 +1916,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1868,6 +1936,10 @@ spec: resources: {} securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1982,9 +2054,9 @@ spec: terminationMessagePolicy: FallbackToLogsOnError serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity diff --git a/cli/cmd/testdata/install_ha_output.golden b/cli/cmd/testdata/install_ha_output.golden index fec9a14e0..823f377da 100644 --- a/cli/cmd/testdata/install_ha_output.golden +++ b/cli/cmd/testdata/install_ha_output.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: proxy-injector + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: linkerd + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: sp-validator + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: linkerd + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### @@ -1663,7 +1727,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1690,6 +1753,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1810,6 +1876,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity @@ -1886,7 +1955,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1910,6 +1978,10 @@ spec: memory: 50Mi securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -2027,9 +2099,9 @@ spec: terminationMessagePolicy: FallbackToLogsOnError serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity diff --git a/cli/cmd/testdata/install_ha_with_overrides_output.golden b/cli/cmd/testdata/install_ha_with_overrides_output.golden index 2770a4f97..bf1987382 100644 --- a/cli/cmd/testdata/install_ha_with_overrides_output.golden +++ b/cli/cmd/testdata/install_ha_with_overrides_output.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: proxy-injector + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: linkerd + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: sp-validator + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: linkerd + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### @@ -1663,7 +1727,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1690,6 +1753,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1810,6 +1876,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity @@ -1886,7 +1955,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1910,6 +1978,10 @@ spec: memory: 50Mi securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -2027,9 +2099,9 @@ spec: terminationMessagePolicy: FallbackToLogsOnError serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity diff --git a/cli/cmd/testdata/install_no_init_container.golden b/cli/cmd/testdata/install_no_init_container.golden index 8364fbae5..9d196cd4f 100644 --- a/cli/cmd/testdata/install_no_init_container.golden +++ b/cli/cmd/testdata/install_no_init_container.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: proxy-injector + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: linkerd + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: sp-validator + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: linkerd + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### @@ -1480,7 +1544,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1504,6 +1567,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1591,6 +1657,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity @@ -1667,7 +1736,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:install-control-plane-version imagePullPolicy: IfNotPresent @@ -1688,6 +1756,10 @@ spec: resources: {} securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1772,9 +1844,9 @@ spec: name: linkerd-identity-end-entity serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity diff --git a/cli/cmd/testdata/install_output.golden b/cli/cmd/testdata/install_output.golden index f26e20107..bd7f291b0 100644 --- a/cli/cmd/testdata/install_output.golden +++ b/cli/cmd/testdata/install_output.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: Namespace --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: Namespace + labels: + ControllerComponentLabel: proxy-injector + annotations: + CreatedByAnnotation: CliVersion +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: Namespace + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: Namespace --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: Namespace + labels: + ControllerComponentLabel: sp-validator + annotations: + CreatedByAnnotation: CliVersion +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: Namespace + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### @@ -1456,7 +1520,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=Namespace - -log-level=ControllerLogLevel image: ControllerImage imagePullPolicy: ImagePullPolicy @@ -1480,6 +1543,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1564,6 +1630,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls status: {} --- kind: Service @@ -1638,7 +1707,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=Namespace - -log-level=ControllerLogLevel image: ControllerImage imagePullPolicy: ImagePullPolicy @@ -1659,6 +1727,10 @@ spec: resources: {} securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1740,9 +1812,9 @@ spec: terminationMessagePolicy: FallbackToLogsOnError serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls status: {} --- ### diff --git a/cli/cmd/testdata/upgrade_default.golden b/cli/cmd/testdata/upgrade_default.golden index 37db3564d..1fef2c244 100644 --- a/cli/cmd/testdata/upgrade_default.golden +++ b/cli/cmd/testdata/upgrade_default.golden @@ -282,6 +282,38 @@ metadata: name: linkerd-proxy-injector namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-proxy-injector-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: proxy-injector + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJveHkgaW5qZWN0b3IgY3J0 + key.pem: cHJveHkgaW5qZWN0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: linkerd-proxy-injector-webhook-config +webhooks: +- name: linkerd-proxy-injector.linkerd.io + clientConfig: + service: + name: linkerd-proxy-injector + namespace: linkerd + path: "/" + caBundle: cHJveHkgaW5qZWN0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +--- ### ### Service Profile Validator RBAC ### @@ -318,6 +350,38 @@ metadata: name: linkerd-sp-validator namespace: linkerd --- +kind: Secret +apiVersion: v1 +metadata: + name: linkerd-sp-validator-tls + namespace: linkerd + labels: + linkerd.io/control-plane-component: sp-validator + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined +type: Opaque +data: + crt.pem: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + key.pem: cHJvZmlsZSB2YWxpZGF0b3Iga2V5 +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: linkerd-sp-validator-webhook-config +webhooks: +- name: linkerd-sp-validator.linkerd.io + clientConfig: + service: + name: linkerd-sp-validator + namespace: linkerd + path: "/" + caBundle: cHJvZmlsZSB2YWxpZGF0b3IgY3J0 + rules: + - operations: [ "CREATE" , "UPDATE" ] + apiGroups: ["linkerd.io"] + apiVersions: ["v1alpha1"] + resources: ["serviceprofiles"] +--- ### ### Tap RBAC ### @@ -1635,7 +1699,6 @@ spec: containers: - args: - proxy-injector - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:UPGRADE-CONTROL-PLANE-VERSION imagePullPolicy: IfNotPresent @@ -1659,6 +1722,9 @@ spec: volumeMounts: - mountPath: /var/run/linkerd/config name: config + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1777,6 +1843,9 @@ spec: - configMap: name: linkerd-config name: config + - name: tls + secret: + secretName: linkerd-proxy-injector-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity @@ -1853,7 +1922,6 @@ spec: containers: - args: - sp-validator - - -controller-namespace=linkerd - -log-level=info image: gcr.io/linkerd-io/controller:UPGRADE-CONTROL-PLANE-VERSION imagePullPolicy: IfNotPresent @@ -1874,6 +1942,10 @@ spec: resources: {} securityContext: runAsUser: 2103 + volumeMounts: + - mountPath: /var/run/linkerd/tls + name: tls + readOnly: true - env: - name: LINKERD2_PROXY_LOG value: warn,linkerd2_proxy=info @@ -1989,9 +2061,9 @@ spec: terminationMessagePolicy: FallbackToLogsOnError serviceAccountName: linkerd-sp-validator volumes: - - configMap: - name: linkerd-config - name: config + - name: tls + secret: + secretName: linkerd-sp-validator-tls - emptyDir: medium: Memory name: linkerd-identity-end-entity diff --git a/cli/cmd/upgrade.go b/cli/cmd/upgrade.go index 18cb87311..d5e6049fa 100644 --- a/cli/cmd/upgrade.go +++ b/cli/cmd/upgrade.go @@ -13,6 +13,7 @@ import ( "github.com/linkerd/linkerd2/pkg/version" "github.com/spf13/cobra" "github.com/spf13/pflag" + kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) @@ -27,12 +28,15 @@ const ( type upgradeOptions struct { manifests string *installOptions + + verifyTLS func(tls *tlsValues, service string) error } func newUpgradeOptionsWithDefaults() *upgradeOptions { return &upgradeOptions{ manifests: "", installOptions: newInstallOptionsWithDefaults(), + verifyTLS: verifyWebhookTLS, } } @@ -236,6 +240,21 @@ func (options *upgradeOptions) validateAndBuild(stage string, k kubernetes.Inter return nil, nil, fmt.Errorf("could not build install configuration: %s", err) } values.Identity = identity + + // if exist, re-use the proxy injector and profile validator TLS secrets, + // otherwise, generate new ones. + proxyInjectorTLS, err := fetchWebhookTLS(k, k8s.ProxyInjectorWebhookServiceName, options) + if err != nil { + return nil, nil, fmt.Errorf("could not fetch existing proxy injector secret: %s", err) + } + values.ProxyInjector = &proxyInjectorValues{proxyInjectorTLS} + + profileValidatorTLS, err := fetchWebhookTLS(k, k8s.SPValidatorWebhookServiceName, options) + if err != nil { + return nil, nil, fmt.Errorf("could not fetch existing profile validator secret: %s", err) + } + values.ProfileValidator = &profileValidatorValues{profileValidatorTLS} + values.stage = stage return values, configs, nil @@ -281,6 +300,36 @@ func fetchConfigs(k kubernetes.Interface) (*pb.All, error) { return config.FromConfigMap(configMap.Data) } +func fetchWebhookTLS(k kubernetes.Interface, webhook string, options *upgradeOptions) (*tlsValues, error) { + + var value *tlsValues + + secret, err := k.CoreV1(). + Secrets(controlPlaneNamespace). + Get(webhookSecretName(webhook), metav1.GetOptions{}) + if err != nil { + if !kerrors.IsNotFound(err) { + return nil, err + } + + value, err = options.generateWebhookTLS(webhook) + if err != nil { + return nil, err + } + } else { + value = &tlsValues{ + KeyPEM: string(secret.Data["key.pem"]), + CrtPEM: string(secret.Data["crt.pem"]), + } + } + + if err := options.verifyTLS(value, webhook); err != nil { + return nil, err + } + + return value, nil +} + // fetchIdentityValue checks the kubernetes API to fetch an existing // linkerd identity configuration. // diff --git a/cli/cmd/upgrade_test.go b/cli/cmd/upgrade_test.go index 804259320..9ed3eed37 100644 --- a/cli/cmd/upgrade_test.go +++ b/cli/cmd/upgrade_test.go @@ -24,6 +24,10 @@ func testUpgradeOptions() *upgradeOptions { o := newUpgradeOptionsWithDefaults() o.controlPlaneVersion = upgradeControlPlaneVersion o.proxyVersion = upgradeProxyVersion + o.generateWebhookTLS = fakeGenerateWebhookTLS + o.verifyTLS = func(tls *tlsValues, service string) error { + return nil + } return o } diff --git a/controller/cmd/proxy-injector/main.go b/controller/cmd/proxy-injector/main.go index ae070f47e..518c478a0 100644 --- a/controller/cmd/proxy-injector/main.go +++ b/controller/cmd/proxy-injector/main.go @@ -3,21 +3,13 @@ package main import ( "github.com/linkerd/linkerd2/controller/k8s" injector "github.com/linkerd/linkerd2/controller/proxy-injector" - "github.com/linkerd/linkerd2/controller/proxy-injector/tmpl" "github.com/linkerd/linkerd2/controller/webhook" - pkgK8s "github.com/linkerd/linkerd2/pkg/k8s" ) func main() { - config := &webhook.Config{ - TemplateStr: tmpl.MutatingWebhookConfigurationSpec, - Ops: &injector.Ops{}, - } webhook.Launch( - config, []k8s.APIResource{k8s.NS, k8s.RS}, 9995, - pkgK8s.ProxyInjectorWebhookServiceName, injector.Inject, ) } diff --git a/controller/cmd/sp-validator/main.go b/controller/cmd/sp-validator/main.go index 3ff04c065..ed97c940e 100644 --- a/controller/cmd/sp-validator/main.go +++ b/controller/cmd/sp-validator/main.go @@ -2,21 +2,13 @@ package main import ( validator "github.com/linkerd/linkerd2/controller/sp-validator" - "github.com/linkerd/linkerd2/controller/sp-validator/tmpl" "github.com/linkerd/linkerd2/controller/webhook" - pkgK8s "github.com/linkerd/linkerd2/pkg/k8s" ) func main() { - config := &webhook.Config{ - TemplateStr: tmpl.ValidatingWebhookConfigurationSpec, - Ops: &validator.Ops{}, - } webhook.Launch( - config, nil, 9997, - pkgK8s.SPValidatorWebhookServiceName, validator.AdmitSP, ) } diff --git a/controller/proxy-injector/tmpl/mutating_webhook_configuration.go b/controller/proxy-injector/tmpl/mutating_webhook_configuration.go deleted file mode 100644 index 37638832a..000000000 --- a/controller/proxy-injector/tmpl/mutating_webhook_configuration.go +++ /dev/null @@ -1,24 +0,0 @@ -package tmpl - -// MutatingWebhookConfigurationSpec provides a template for a -// MutatingWebhookConfiguration. -var MutatingWebhookConfigurationSpec = ` -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: MutatingWebhookConfiguration -metadata: - name: {{ .WebhookConfigName }} - labels: - linkerd.io/control-plane-component: proxy-injector -webhooks: -- name: linkerd-proxy-injector.linkerd.io - clientConfig: - service: - name: linkerd-proxy-injector - namespace: {{ .ControllerNamespace }} - path: "/" - caBundle: {{ .CABundle }} - rules: - - operations: [ "CREATE" , "UPDATE" ] - apiGroups: [""] - apiVersions: ["v1"] - resources: ["pods"]` diff --git a/controller/sp-validator/tmpl/validating_webhook_configuration.go b/controller/sp-validator/tmpl/validating_webhook_configuration.go deleted file mode 100644 index 997beb737..000000000 --- a/controller/sp-validator/tmpl/validating_webhook_configuration.go +++ /dev/null @@ -1,24 +0,0 @@ -package tmpl - -// ValidatingWebhookConfigurationSpec provides a template for a -// ValidatingWebhookConfiguration. -var ValidatingWebhookConfigurationSpec = ` -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: ValidatingWebhookConfiguration -metadata: - name: {{ .WebhookConfigName }} - labels: - linkerd.io/control-plane-component: sp-validator -webhooks: -- name: linkerd-sp-validator.linkerd.io - clientConfig: - service: - name: linkerd-sp-validator - namespace: {{ .ControllerNamespace }} - path: "/" - caBundle: {{ .CABundle }} - rules: - - operations: [ "CREATE" , "UPDATE" ] - apiGroups: ["linkerd.io"] - apiVersions: ["v1alpha1"] - resources: ["serviceprofiles"]` diff --git a/controller/webhook/config.go b/controller/webhook/config.go deleted file mode 100644 index e9994b684..000000000 --- a/controller/webhook/config.go +++ /dev/null @@ -1,78 +0,0 @@ -package webhook - -import ( - "bytes" - "encoding/base64" - "html/template" - - "github.com/linkerd/linkerd2/pkg/tls" - log "github.com/sirupsen/logrus" - apierrors "k8s.io/apimachinery/pkg/api/errors" - clientArv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" -) - -// ConfigOps declares the methods used to manage the webhook configs in the cluster -type ConfigOps interface { - Create(clientArv1beta1.AdmissionregistrationV1beta1Interface, *bytes.Buffer) (string, error) - Delete(clientArv1beta1.AdmissionregistrationV1beta1Interface) error - Exists(clientArv1beta1.AdmissionregistrationV1beta1Interface) error - Name() string -} - -// Config contains all the necessary data to build and persist the webhook resource -type Config struct { - TemplateStr string - Ops ConfigOps - client clientArv1beta1.AdmissionregistrationV1beta1Interface - controllerNamespace string - rootCA *tls.CA -} - -// Create deletes the webhook config if it already exists and then creates -// a new one -func (c *Config) Create() (string, error) { - exists, err := c.Exists() - if err != nil { - return "", err - } - - if exists { - log.Info("deleting existing webhook configuration") - if err := c.Ops.Delete(c.client); err != nil { - return "", err - } - } - - var ( - buf = &bytes.Buffer{} - trustAnchor = []byte(c.rootCA.Cred.EncodeCertificatePEM()) - spec = struct { - WebhookConfigName string - ControllerNamespace string - CABundle string - }{ - WebhookConfigName: c.Ops.Name(), - ControllerNamespace: c.controllerNamespace, - CABundle: base64.StdEncoding.EncodeToString(trustAnchor), - } - ) - t := template.Must(template.New("webhook").Parse(c.TemplateStr)) - if err := t.Execute(buf, spec); err != nil { - return "", err - } - - return c.Ops.Create(c.client, buf) -} - -// Exists returns true if the webhook already exists -func (c *Config) Exists() (bool, error) { - if err := c.Ops.Exists(c.client); err != nil { - if apierrors.IsNotFound(err) { - return false, nil - } - - return false, err - } - - return true, nil -} diff --git a/controller/webhook/config_test.go b/controller/webhook/config_test.go deleted file mode 100644 index d7a12b2ff..000000000 --- a/controller/webhook/config_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package webhook - -import ( - "fmt" - "testing" - - "github.com/linkerd/linkerd2/controller/k8s" - injector "github.com/linkerd/linkerd2/controller/proxy-injector" - injectorTmpl "github.com/linkerd/linkerd2/controller/proxy-injector/tmpl" - validator "github.com/linkerd/linkerd2/controller/sp-validator" - validatorTmpl "github.com/linkerd/linkerd2/controller/sp-validator/tmpl" - "github.com/linkerd/linkerd2/pkg/tls" -) - -func TestCreate(t *testing.T) { - k8sAPI, err := k8s.NewFakeAPI() - if err != nil { - panic(err) - } - - rootCA, err := tls.GenerateRootCAWithDefaults("Test CA") - if err != nil { - t.Fatalf("failed to create root CA: %s", err) - } - - testCases := []struct { - testName string - templateStr string - ops ConfigOps - }{ - { - testName: "Mutating webhook", - templateStr: injectorTmpl.MutatingWebhookConfigurationSpec, - ops: &injector.Ops{}, - }, - { - testName: "Validating webhook", - templateStr: validatorTmpl.ValidatingWebhookConfigurationSpec, - ops: &validator.Ops{}, - }, - } - - for _, tc := range testCases { - tc := tc // pin - t.Run(fmt.Sprintf(tc.testName), func(t *testing.T) { - webhookConfig := &Config{ - TemplateStr: tc.templateStr, - Ops: tc.ops, - client: k8sAPI.Client.AdmissionregistrationV1beta1(), - controllerNamespace: "linkerd", - rootCA: rootCA, - } - - // expect configuration to not exist - exists, err := webhookConfig.Exists() - if err != nil { - t.Fatal("Unexpected error: ", err) - } - if exists { - t.Error("Unexpected webhook configuration. Expect resource to not exist") - } - - // create the webhook configuration - if _, err := webhookConfig.Create(); err != nil { - t.Fatal("Unexpected error: ", err) - } - - // expect webhook configuration to exist - exists, err = webhookConfig.Exists() - if err != nil { - t.Fatal("Unexpected error: ", err) - } - if !exists { - t.Error("Expected webhook configuration to exist") - } - }) - } -} diff --git a/controller/webhook/launcher.go b/controller/webhook/launcher.go index 4aa0f1575..4e188c207 100644 --- a/controller/webhook/launcher.go +++ b/controller/webhook/launcher.go @@ -12,16 +12,16 @@ import ( "github.com/linkerd/linkerd2/controller/k8s" "github.com/linkerd/linkerd2/pkg/admin" "github.com/linkerd/linkerd2/pkg/flags" + pkgk8s "github.com/linkerd/linkerd2/pkg/k8s" "github.com/linkerd/linkerd2/pkg/tls" log "github.com/sirupsen/logrus" ) // Launch sets up and starts the webhook and metrics servers -func Launch(config *Config, APIResources []k8s.APIResource, metricsPort uint32, serviceName string, handler handlerFunc) { +func Launch(APIResources []k8s.APIResource, metricsPort uint32, handler handlerFunc) { metricsAddr := flag.String("metrics-addr", fmt.Sprintf(":%d", metricsPort), "address to serve scrapable metrics on") addr := flag.String("addr", ":8443", "address to serve on") kubeconfig := flag.String("kubeconfig", "", "path to kubeconfig") - controllerNamespace := flag.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed") flags.ConfigureAndParse() stop := make(chan os.Signal, 1) @@ -33,22 +33,12 @@ func Launch(config *Config, APIResources []k8s.APIResource, metricsPort uint32, log.Fatalf("failed to initialize Kubernetes API: %s", err) } - rootCA, err := tls.GenerateRootCAWithDefaults(serviceName) + cred, err := tls.ReadPEMCreds(pkgk8s.MountPathTLSKeyPEM, pkgk8s.MountPathTLSCrtPEM) if err != nil { - log.Fatalf("failed to create root CA: %s", err) + log.Fatalf("failed to read TLS secrets: %s", err) } - config.client = k8sAPI.Client.AdmissionregistrationV1beta1() - config.controllerNamespace = *controllerNamespace - config.rootCA = rootCA - - selfLink, err := config.Create() - if err != nil { - log.Fatalf("failed to create the webhook configurations resource: %s", err) - } - log.Infof("created webhook configuration: %s", selfLink) - - s, err := NewServer(k8sAPI, *addr, serviceName, *controllerNamespace, rootCA, handler) + s, err := NewServer(k8sAPI, *addr, cred, handler) if err != nil { log.Fatalf("failed to initialize the webhook server: %s", err) } diff --git a/controller/webhook/server.go b/controller/webhook/server.go index 291243e14..93d207a50 100644 --- a/controller/webhook/server.go +++ b/controller/webhook/server.go @@ -4,7 +4,6 @@ import ( "context" "crypto/tls" "encoding/json" - "fmt" "io/ioutil" "net/http" @@ -21,24 +20,30 @@ type handlerFunc func(*k8s.API, *admissionv1beta1.AdmissionRequest) (*admissionv // Server describes the https server implementing the webhook type Server struct { *http.Server - api *k8s.API - handler handlerFunc - controllerNamespace string + api *k8s.API + handler handlerFunc } // NewServer returns a new instance of Server -func NewServer(api *k8s.API, addr, name, controllerNamespace string, rootCA *pkgTls.CA, handler handlerFunc) (*Server, error) { - c, err := tlsConfig(rootCA, name, controllerNamespace) +func NewServer(api *k8s.API, addr string, cred *pkgTls.Cred, handler handlerFunc) (*Server, error) { + var ( + certPEM = cred.EncodePEM() + keyPEM = cred.EncodePrivateKeyPEM() + ) + + cert, err := tls.X509KeyPair([]byte(certPEM), []byte(keyPEM)) if err != nil { return nil, err } server := &http.Server{ - Addr: addr, - TLSConfig: c, + Addr: addr, + TLSConfig: &tls.Config{ + Certificates: []tls.Certificate{cert}, + }, } - s := &Server{server, api, handler, controllerNamespace} + s := &Server{server, api, handler} s.Handler = http.HandlerFunc(s.serve) return s, nil } @@ -123,29 +128,6 @@ func (s *Server) Shutdown(ctx context.Context) error { return s.Server.Shutdown(ctx) } -func tlsConfig(rootCA *pkgTls.CA, name, controllerNamespace string) (*tls.Config, error) { - // must use the service short name in this TLS identity as the k8s api server - // looks for the webhook at ..svc, without the cluster - // domain. - dnsName := fmt.Sprintf("%s.%s.svc", name, controllerNamespace) - - cred, err := rootCA.GenerateEndEntityCred(dnsName) - if err != nil { - return nil, err - } - - certPEM := cred.EncodePEM() - keyPEM := cred.EncodePrivateKeyPEM() - cert, err := tls.X509KeyPair([]byte(certPEM), []byte(keyPEM)) - if err != nil { - return nil, err - } - - return &tls.Config{ - Certificates: []tls.Certificate{cert}, - }, nil -} - func decode(data []byte) (*admissionv1beta1.AdmissionReview, error) { var admissionReview admissionv1beta1.AdmissionReview err := yaml.Unmarshal(data, &admissionReview) diff --git a/controller/webhook/server_test.go b/controller/webhook/server_test.go index 8884522ff..a18b6398a 100644 --- a/controller/webhook/server_test.go +++ b/controller/webhook/server_test.go @@ -18,7 +18,7 @@ func TestServe(t *testing.T) { if err != nil { panic(err) } - testServer := &Server{nil, k8sAPI, nil, "linkerd"} + testServer := &Server{nil, k8sAPI, nil} in := bytes.NewReader(nil) request := httptest.NewRequest(http.MethodGet, "/", in) @@ -38,7 +38,7 @@ func TestServe(t *testing.T) { func TestShutdown(t *testing.T) { server := &http.Server{Addr: ":0"} - testServer := &Server{server, nil, nil, "linkerd"} + testServer := &Server{server, nil, nil} go func() { if err := testServer.ListenAndServe(); err != nil { diff --git a/pkg/k8s/labels.go b/pkg/k8s/labels.go index fae10461a..c07246b72 100644 --- a/pkg/k8s/labels.go +++ b/pkg/k8s/labels.go @@ -240,6 +240,12 @@ const ( // store identity credentials. MountPathEndEntity = MountPathBase + "/identity/end-entity" + // MountPathTLSKeyPEM is the path at which the TLS key PEM file is mounted. + MountPathTLSKeyPEM = MountPathBase + "/tls/key.pem" + + // MountPathTLSCrtPEM is the path at which the TLS cert PEM file is mounted. + MountPathTLSCrtPEM = MountPathBase + "/tls/crt.pem" + // IdentityServiceAccountTokenPath is the path to the kubernetes service // account token used by proxies to provision identity. //