diff --git a/multicluster/cmd/install.go b/multicluster/cmd/install.go index 638d432f447d0..dd6f1d1bfd3bc 100644 --- a/multicluster/cmd/install.go +++ b/multicluster/cmd/install.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "io" "os" "path" "time" @@ -68,89 +69,7 @@ A full list of configurable values can be found at https://github.com/linkerd/li APIAddr: apiAddr, RetryDeadline: time.Now().Add(wait), }) - - values, err := buildMulticlusterInstallValues(cmd.Context(), options) - - if err != nil { - return err - } - - // Render raw values and create chart config - rawValues, err := yaml.Marshal(values) - if err != nil { - return err - } - - files := []*chartloader.BufferedFile{ - {Name: chartutil.ChartfileName}, - {Name: "templates/namespace.yaml"}, - {Name: "templates/gateway.yaml"}, - {Name: "templates/proxy-admin-policy.yaml"}, - {Name: "templates/gateway-policy.yaml"}, - {Name: "templates/psp.yaml"}, - {Name: "templates/remote-access-service-mirror-rbac.yaml"}, - {Name: "templates/link-crd.yaml"}, - {Name: "templates/service-mirror-policy.yaml"}, - } - - var partialFiles []*loader.BufferedFile - for _, template := range charts.L5dPartials { - partialFiles = append(partialFiles, - &loader.BufferedFile{Name: template}, - ) - } - - // Load all multicluster install chart files into buffer - if err := charts.FilesReader(static.Templates, helmMulticlusterDefaultChartName+"/", files); err != nil { - return err - } - - // Load all partial chart files into buffer - if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil { - return err - } - - // Create a Chart obj from the files - chart, err := loader.LoadFiles(append(files, partialFiles...)) - if err != nil { - return err - } - - // Store final Values generated from values.yaml and CLI flags - err = yaml.Unmarshal(rawValues, &chart.Values) - if err != nil { - return err - } - - // Create values override - valuesOverrides, err := valuesOptions.MergeValues(nil) - if err != nil { - return err - } - - vals, err := chartutil.CoalesceValues(chart, valuesOverrides) - if err != nil { - return err - } - - // Attach the final values into the `Values` field for rendering to work - renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) - if err != nil { - return err - } - - // Merge templates and inject - var buf bytes.Buffer - for _, tmpl := range chart.Templates { - t := path.Join(chart.Metadata.Name, tmpl.Name) - if _, err := buf.WriteString(renderedTemplates[t]); err != nil { - return err - } - } - stdout.Write(buf.Bytes()) - stdout.Write([]byte("---\n")) - - return nil + return install(cmd.Context(), stdout, options, valuesOptions) }, } @@ -178,6 +97,94 @@ A full list of configurable values can be found at https://github.com/linkerd/li return cmd } +func install(ctx context.Context, w io.Writer, options *multiclusterInstallOptions, valuesOptions valuespkg.Options) error { + values, err := buildMulticlusterInstallValues(ctx, options) + if err != nil { + return err + } + + // Create values override + valuesOverrides, err := valuesOptions.MergeValues(nil) + if err != nil { + return err + } + + return render(w, values, valuesOverrides) +} + +func render(w io.Writer, values *multicluster.Values, valuesOverrides map[string]interface{}) error { + files := []*chartloader.BufferedFile{ + {Name: chartutil.ChartfileName}, + {Name: chartutil.ValuesfileName}, + {Name: "templates/namespace.yaml"}, + {Name: "templates/gateway.yaml"}, + {Name: "templates/proxy-admin-policy.yaml"}, + {Name: "templates/gateway-policy.yaml"}, + {Name: "templates/psp.yaml"}, + {Name: "templates/remote-access-service-mirror-rbac.yaml"}, + {Name: "templates/link-crd.yaml"}, + {Name: "templates/service-mirror-policy.yaml"}, + } + + var partialFiles []*loader.BufferedFile + for _, template := range charts.L5dPartials { + partialFiles = append(partialFiles, + &loader.BufferedFile{Name: template}, + ) + } + + // Load all multicluster install chart files into buffer + if err := charts.FilesReader(static.Templates, helmMulticlusterDefaultChartName+"/", files); err != nil { + return err + } + + // Load all partial chart files into buffer + if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil { + return err + } + + // Create a Chart obj from the files + chart, err := loader.LoadFiles(append(files, partialFiles...)) + if err != nil { + return err + } + + // Render raw values and create chart config + rawValues, err := yaml.Marshal(values) + if err != nil { + return err + } + // Store final Values generated from values.yaml and CLI flags + err = yaml.Unmarshal(rawValues, &chart.Values) + if err != nil { + return err + } + + vals, err := chartutil.CoalesceValues(chart, valuesOverrides) + if err != nil { + return err + } + + // Attach the final values into the `Values` field for rendering to work + renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) + if err != nil { + return err + } + + // Merge templates and inject + var buf bytes.Buffer + for _, tmpl := range chart.Templates { + t := path.Join(chart.Metadata.Name, tmpl.Name) + if _, err := buf.WriteString(renderedTemplates[t]); err != nil { + return err + } + } + w.Write(buf.Bytes()) + w.Write([]byte("---\n")) + + return nil +} + func newMulticlusterInstallOptionsWithDefault() (*multiclusterInstallOptions, error) { defaults, err := multicluster.NewInstallValues() if err != nil { diff --git a/multicluster/cmd/install_test.go b/multicluster/cmd/install_test.go new file mode 100644 index 0000000000000..849167a11acac --- /dev/null +++ b/multicluster/cmd/install_test.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "bytes" + "fmt" + "testing" + + multicluster "github.com/linkerd/linkerd2/multicluster/values" + "github.com/linkerd/linkerd2/pkg/charts" +) + +func TestRender(t *testing.T) { + // pin values that are changed by render functions on each test run + defaultValues := map[string]interface{}{} + + testCases := []struct { + values map[string]interface{} + multiclusterValues *multicluster.Values + goldenFileName string + }{ + { + nil, + nil, + "install_default.golden", + }, + { + map[string]interface{}{ + "enablePSP": "true", + }, + nil, + "install_psp.golden", + }, + } + + for i, tc := range testCases { + tc := tc // pin + t.Run(fmt.Sprintf("%d: %s", i, tc.goldenFileName), func(t *testing.T) { + var buf bytes.Buffer + // Merge overrides with default + if err := render(&buf, tc.multiclusterValues, charts.MergeMaps(defaultValues, tc.values)); err != nil { + t.Fatalf("Failed to render templates: %v", err) + } + testDataDiffer.DiffTestdata(t, tc.goldenFileName, buf.String()) + }) + } +} diff --git a/multicluster/cmd/main_test.go b/multicluster/cmd/main_test.go new file mode 100644 index 0000000000000..676a7e0af7e5d --- /dev/null +++ b/multicluster/cmd/main_test.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "flag" + "os" + "testing" + + "github.com/linkerd/linkerd2/testutil" +) + +var ( + testDataDiffer testutil.TestDataDiffer +) + +// TestMain parses flags before running tests +func TestMain(m *testing.M) { + flag.BoolVar(&testDataDiffer.UpdateFixtures, "update", false, "update text fixtures in place") + prettyDiff := os.Getenv("LINKERD_TEST_PRETTY_DIFF") != "" + flag.BoolVar(&testDataDiffer.PrettyDiff, "pretty-diff", prettyDiff, "display the full text when diffing") + flag.StringVar(&testDataDiffer.RejectPath, "reject-path", "", "write results for failed tests to this path (path is relative to the test location)") + flag.Parse() + os.Exit(m.Run()) +} diff --git a/multicluster/cmd/testdata/install_default.golden b/multicluster/cmd/testdata/install_default.golden new file mode 100644 index 0000000000000..816e50914b9aa --- /dev/null +++ b/multicluster/cmd/testdata/install_default.golden @@ -0,0 +1,366 @@ +kind: Namespace +apiVersion: v1 +metadata: + name: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + labels: + app.kubernetes.io/name: gateway + app.kubernetes.io/part-of: Linkerd + app.kubernetes.io/version: linkerdVersionValue + linkerd.io/control-plane-component: gateway + app: linkerd-gateway + linkerd.io/extension: multicluster + name: linkerd-gateway + namespace: linkerd-multicluster +spec: + replicas: 1 + selector: + matchLabels: + app: linkerd-gateway + template: + metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + linkerd.io/inject: enabled + config.linkerd.io/proxy-require-identity-inbound-ports: "4143" + config.linkerd.io/enable-gateway: "true" + labels: + app: linkerd-gateway + spec: + containers: + - name: pause + image: gcr.io/google_containers/pause + serviceAccountName: linkerd-gateway +--- +apiVersion: v1 +kind: Service +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + mirror.linkerd.io/gateway-identity: linkerd-gateway.linkerd-multicluster.serviceaccount.identity.linkerd.cluster.local + mirror.linkerd.io/probe-period: "3" + mirror.linkerd.io/probe-path: /ready + mirror.linkerd.io/multicluster-gateway: "true" + linkerd.io/control-plane-component: gateway + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + ports: + - name: mc-gateway + port: 4143 + protocol: TCP + - name: mc-probe + port: 4191 + protocol: TCP + selector: + app: linkerd-gateway + type: LoadBalancer +--- +kind: ServiceAccount +apiVersion: v1 +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: gateway-proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + server: + name: service-mirror-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-proxy + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: linkerd-gateway + client: + meshTLS: + identities: + - '*' + networks: + # Change this to the source cluster cidrs pointing to this gateway. + # Note that the source IP in some providers (e.g. GKE) will be the local + # node's IP and not the source cluster's + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway-probe + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # allows probes from outside the cluster, as long as they have an identity + meshTLS: + identities: + - '*' + networks: + # cf note for linkerd-gateway ServerAuthorization + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +rules: +- apiGroups: [""] + resources: ["services", "endpoints"] + verbs: ["list", "get", "watch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] + resourceNames: ["linkerd-config"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: linkerd-service-mirror-remote-access-default +subjects: +- kind: ServiceAccount + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster +--- +### +### Link CRD +### +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: links.multicluster.linkerd.io + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + group: multicluster.linkerd.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + clusterCredentialsSecret: + description: Kubernetes secret of target cluster + type: string + gatewayAddress: + description: Gateway address of target cluster + type: string + gatewayIdentity: + description: Gateway Identity FQDN + type: string + gatewayPort: + description: Gateway Port + type: string + probeSpec: + description: Spec for gateway health probe + type: object + properties: + path: + description: Path of remote gateway health endpoint + type: string + period: + description: Interval in between probe requests + type: string + port: + description: Port of remote gateway health endpoint + type: string + selector: + description: Kubernetes Label Selector + type: object + properties: + matchExpressions: + description: List of selector requirements + type: array + items: + description: A selector item requires a key and an operator + type: object + required: + - key + - operator + properties: + key: + description: Label key that selector should apply to + type: string + operator: + description: Evaluation of a label in relation to set + type: string + targetClusterName: + description: Name of target cluster to link to + type: string + targetClusterDomain: + description: Domain name of target cluster to link to + type: string + targetClusterLinkerdNamespace: + description: Name of namespace Linkerd control plane is installed in on target cluster + type: string + scope: Namespaced + names: + plural: links + singular: link + kind: Link +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: admin-http + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + server: + name: service-mirror + client: + # In order to use `linkerd mc gateways` you need viz' Prometheus instance + # to be able to reach the service-mirror. In order to also have a separate + # Prometheus scrape the service-mirror an additional ServerAuthorization + # resource should be created. + meshTLS: + serviceAccounts: + - name: prometheus + namespace: linkerd-viz +--- diff --git a/multicluster/cmd/testdata/install_psp.golden b/multicluster/cmd/testdata/install_psp.golden new file mode 100644 index 0000000000000..3cf9557f6047d --- /dev/null +++ b/multicluster/cmd/testdata/install_psp.golden @@ -0,0 +1,397 @@ +kind: Namespace +apiVersion: v1 +metadata: + name: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + labels: + app.kubernetes.io/name: gateway + app.kubernetes.io/part-of: Linkerd + app.kubernetes.io/version: linkerdVersionValue + linkerd.io/control-plane-component: gateway + app: linkerd-gateway + linkerd.io/extension: multicluster + name: linkerd-gateway + namespace: linkerd-multicluster +spec: + replicas: 1 + selector: + matchLabels: + app: linkerd-gateway + template: + metadata: + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue + linkerd.io/inject: enabled + config.linkerd.io/proxy-require-identity-inbound-ports: "4143" + config.linkerd.io/enable-gateway: "true" + labels: + app: linkerd-gateway + spec: + containers: + - name: pause + image: gcr.io/google_containers/pause + serviceAccountName: linkerd-gateway +--- +apiVersion: v1 +kind: Service +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + mirror.linkerd.io/gateway-identity: linkerd-gateway.linkerd-multicluster.serviceaccount.identity.linkerd.cluster.local + mirror.linkerd.io/probe-period: "3" + mirror.linkerd.io/probe-path: /ready + mirror.linkerd.io/multicluster-gateway: "true" + linkerd.io/control-plane-component: gateway + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + ports: + - name: mc-gateway + port: 4143 + protocol: TCP + - name: mc-probe + port: 4191 + protocol: TCP + selector: + app: linkerd-gateway + type: LoadBalancer +--- +kind: ServiceAccount +apiVersion: v1 +metadata: + name: linkerd-gateway + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: gateway-proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: proxy-admin + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: linkerd-admin + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror-proxy-admin + labels: + linkerd.io/extension: multicluster +spec: + server: + name: service-mirror-proxy-admin + client: + # for kubelet probes + unauthenticated: true +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + podSelector: + matchLabels: + app: linkerd-gateway + port: linkerd-proxy + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: linkerd-gateway + client: + meshTLS: + identities: + - '*' + networks: + # Change this to the source cluster cidrs pointing to this gateway. + # Note that the source IP in some providers (e.g. GKE) will be the local + # node's IP and not the source cluster's + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: linkerd-gateway-probe + labels: + linkerd.io/extension: multicluster + app: linkerd-gateway + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + server: + name: gateway-proxy-admin + client: + # allows probes from outside the cluster, as long as they have an identity + meshTLS: + identities: + - '*' + networks: + # cf note for linkerd-gateway ServerAuthorization + - cidr: 0.0.0.0/0 + - cidr: ::/0 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: psp + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster +rules: +- apiGroups: ['policy', 'extensions'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - linkerd-linkerd-control-plane +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multicluster-psp + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + namespace: linkerd-multicluster +roleRef: + kind: Role + name: psp + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: linkerd-gateway + namespace: linkerd-multicluster +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +rules: +- apiGroups: [""] + resources: ["services", "endpoints"] + verbs: ["list", "get", "watch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] + resourceNames: ["linkerd-config"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: linkerd-service-mirror-remote-access-default +subjects: +- kind: ServiceAccount + name: linkerd-service-mirror-remote-access-default + namespace: linkerd-multicluster +--- +### +### Link CRD +### +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: links.multicluster.linkerd.io + labels: + linkerd.io/extension: multicluster + annotations: + linkerd.io/created-by: linkerd/helm linkerdVersionValue +spec: + group: multicluster.linkerd.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + clusterCredentialsSecret: + description: Kubernetes secret of target cluster + type: string + gatewayAddress: + description: Gateway address of target cluster + type: string + gatewayIdentity: + description: Gateway Identity FQDN + type: string + gatewayPort: + description: Gateway Port + type: string + probeSpec: + description: Spec for gateway health probe + type: object + properties: + path: + description: Path of remote gateway health endpoint + type: string + period: + description: Interval in between probe requests + type: string + port: + description: Port of remote gateway health endpoint + type: string + selector: + description: Kubernetes Label Selector + type: object + properties: + matchExpressions: + description: List of selector requirements + type: array + items: + description: A selector item requires a key and an operator + type: object + required: + - key + - operator + properties: + key: + description: Label key that selector should apply to + type: string + operator: + description: Evaluation of a label in relation to set + type: string + targetClusterName: + description: Name of target cluster to link to + type: string + targetClusterDomain: + description: Domain name of target cluster to link to + type: string + targetClusterLinkerdNamespace: + description: Name of namespace Linkerd control plane is installed in on target cluster + type: string + scope: Namespaced + names: + plural: links + singular: link + kind: Link +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + podSelector: + matchLabels: + linkerd.io/control-plane-component: linkerd-service-mirror + port: admin-http + proxyProtocol: HTTP/1 +--- +apiVersion: policy.linkerd.io/v1beta1 +kind: ServerAuthorization +metadata: + namespace: linkerd-multicluster + name: service-mirror + labels: + linkerd.io/control-plane-component: linkerd-service-mirror +spec: + server: + name: service-mirror + client: + # In order to use `linkerd mc gateways` you need viz' Prometheus instance + # to be able to reach the service-mirror. In order to also have a separate + # Prometheus scrape the service-mirror an additional ServerAuthorization + # resource should be created. + meshTLS: + serviceAccounts: + - name: prometheus + namespace: linkerd-viz +---