Introduce AuthorizationPolicy CRDs (#8007)

Issue #7709 proposes new Custom Resource types to support generalized
authorization policies:

- `AuthorizationPolicy`
- `MeshTLSAuthentication`
- `NetworkAuthentication`

This change introduces these CRDs to the default linkerd installation
(via the `linkerd-crds` chart) and updates the policy controller's
to handle these resource types. The policy admission controller
validates that these resource reference only suppported types.

This new functionality is tested at multiple levels:

* `linkerd-policy-controller-k8s-index` includes unit tests for the
  indexer to test how events update the index;
* `linkerd-policy-test` includes integration tests that run in-cluster
  to validate that the gRPC API updates as resources are manipulated;
* `linkerd-policy-test` includes integration tests that exercise the
  admission controller's resource validation; and
* `linkerd-policy-test` includes integration tests that ensure that
  proxies honor authorization resources.

This change does NOT update Linkerd's control plane and extensions to
use these new authorization primitives. Furthermore, the `linkerd` CLI
does not yet support inspecting these new resource types. These
enhancements will be made in followup changes.

Signed-off-by: Oliver Gould <ver@buoyant.io>
This commit is contained in:
Oliver Gould 2022-03-30 12:26:45 -07:00 committed by GitHub
parent 24079ab076
commit c1a1430d1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 6833 additions and 510 deletions

View File

@ -958,6 +958,7 @@ dependencies = [
"futures",
"linkerd-policy-controller-core",
"linkerd2-proxy-api",
"maplit",
"tokio",
"tonic",
"tracing",
@ -989,6 +990,7 @@ dependencies = [
"kubert",
"linkerd-policy-controller-core",
"linkerd-policy-controller-k8s-api",
"maplit",
"parking_lot",
"tokio",
"tokio-stream",

View File

@ -166,6 +166,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -190,6 +193,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -0,0 +1,99 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
{{ include "partials.annotations.created-by" . }}
labels:
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
linkerd.io/control-plane-ns: {{.Release.Namespace}}
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string

View File

@ -0,0 +1,86 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
{{ include "partials.annotations.created-by" . }}
labels:
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
linkerd.io/control-plane-ns: {{.Release.Namespace}}
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string

View File

@ -0,0 +1,53 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
{{ include "partials.annotations.created-by" . }}
labels:
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
linkerd.io/control-plane-ns: {{.Release.Namespace}}
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string

View File

@ -61,6 +61,9 @@ Otherwise, you can use the --ignore-cluster flag to overwrite the existing globa
var (
templatesCrdFiles = []string{
"templates/policy/authorization-policy.yaml",
"templates/policy/meshtls-authentication.yaml",
"templates/policy/network-authentication.yaml",
"templates/policy/server.yaml",
"templates/policy/server-authorization.yaml",
"templates/serviceprofile.yaml",

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -161,6 +161,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -185,6 +188,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -161,6 +161,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -185,6 +188,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,4 +1,248 @@
---
# Source: linkerd-crds/templates/policy/authorization-policy.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/helm linkerd-version
labels:
helm.sh/chart: linkerd-crds-
linkerd.io/control-plane-ns: linkerd-dev
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
# Source: linkerd-crds/templates/policy/meshtls-authentication.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/helm linkerd-version
labels:
helm.sh/chart: linkerd-crds-
linkerd.io/control-plane-ns: linkerd-dev
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
# Source: linkerd-crds/templates/policy/network-authentication.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/helm linkerd-version
labels:
helm.sh/chart: linkerd-crds-
linkerd.io/control-plane-ns: linkerd-dev
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
# Source: linkerd-crds/templates/policy/server.yaml
---
apiVersion: apiextensions.k8s.io/v1

View File

@ -1,4 +1,248 @@
---
# Source: linkerd-crds/templates/policy/authorization-policy.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/helm linkerd-version
labels:
helm.sh/chart: linkerd-crds-
linkerd.io/control-plane-ns: linkerd-dev
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
# Source: linkerd-crds/templates/policy/meshtls-authentication.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/helm linkerd-version
labels:
helm.sh/chart: linkerd-crds-
linkerd.io/control-plane-ns: linkerd-dev
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
# Source: linkerd-crds/templates/policy/network-authentication.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/helm linkerd-version
labels:
helm.sh/chart: linkerd-crds-
linkerd.io/control-plane-ns: linkerd-dev
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
# Source: linkerd-crds/templates/policy/server.yaml
---
apiVersion: apiextensions.k8s.io/v1

View File

@ -161,6 +161,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -185,6 +188,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -161,6 +161,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -185,6 +188,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: CliVersion
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: CliVersion
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: CliVersion
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -856,6 +1094,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -880,6 +1121,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -1,6 +1,244 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: authorizationpolicies.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: AuthorizationPolicy
plural: authorizationpolicies
singular: authorizationpolicy
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
Authorizes clients to communicate with Linkerd-proxied server
resources.
type: object
required: [targetRef, requiredAuthenticationRefs]
properties:
targetRef:
description: >-
TargetRef references a resource to which the authorization
policy applies.
type: object
required: [kind, name]
# Modified from the gateway API.
# Copyright 2020 The Kubernetes Authors
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred.
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
requiredAuthenticationRefs:
description: >-
RequiredAuthenticationRefs enumerates a set of required
authentications. ALL authentications must be satisfied for
the authorization to apply. If any of the referred objects
cannot be found, the authorization will be ignored.
type: array
items:
type: object
required: [kind, name]
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: meshtlsauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: MeshTLSAuthentication
plural: meshtlsauthentications
singular: meshtlsauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
MeshTLSAuthentication defines a list of authenticated client IDs
to be referenced by an `AuthorizationPolicy`. If a client
connection has the mutually-authenticated identity that matches
ANY of the of the provided identities, the connection is
considered authenticated.
type: object
oneOf:
- required: [identities]
- required: [identityRefs]
properties:
identities:
description: >-
Authorizes clients with the provided proxy identity strings
(as provided via MTLS)
The `*` prefix can be used to match all identities in
a domain. An identity string of `*` indicates that
all authentication clients are authorized.
type: array
items:
type: string
pattern: '^(\*|[a-z0-9]([-a-z0-9]*[a-z0-9])?)(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
identityRefs:
type: array
items:
type: object
required:
- kind
properties:
group:
description: >-
Group is the group of the referent. When empty, the
Kubernetes core API group is inferred."
maxLength: 253
pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
type: string
kind:
description: >-
Kind is the kind of the referent.
maxLength: 63
minLength: 1
pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
type: string
name:
description: >-
Name is the name of the referent. When unspecified,
this refers to all resources of the specified Group
and Kind in the specified namespace.
maxLength: 253
minLength: 1
type: string
namespace:
description: >-
Name is the name of the referent. When unspecified,
this authentication refers to the local namespace.
maxLength: 253
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: networkauthentications.policy.linkerd.io
annotations:
linkerd.io/created-by: linkerd/cli dev-undefined
labels:
helm.sh/chart: linkerd-control-plane-1.1.11-edge
linkerd.io/control-plane-ns: linkerd
spec:
group: policy.linkerd.io
scope: Namespaced
names:
kind: NetworkAuthentication
plural: networkauthentications
singular: networkauthentication
shortNames: []
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
description: >-
NetworkAuthentication defines a list of authenticated client
networks to be referenced by an `AuthorizationPolicy`. If a
client connection originates from ANY of the of the provided
networks, the connection is considered authenticated.
type: object
required: [networks]
properties:
networks:
type: array
items:
type: object
required: [cidr]
properties:
cidr:
description: >-
The CIDR of the network to be authorized.
type: string
except:
description: >-
A list of IP networks/addresses not to be included in
the above `cidr`.
type: array
items:
type: string
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.policy.linkerd.io
annotations:
@ -859,6 +1097,9 @@ webhooks:
apiGroups: ["policy.linkerd.io"]
apiVersions: ["v1alpha1", "v1beta1"]
resources:
- authorizationpolicies
- networkauthentications
- meshtlsauthentications
- serverauthorizations
- servers
sideEffects: None
@ -883,6 +1124,9 @@ rules:
- apiGroups:
- policy.linkerd.io
resources:
- authorizationpolicies
- meshtlsauthentications
- networkauthentications
- servers
- serverauthorizations
verbs:

View File

@ -24,9 +24,23 @@ pub type InboundServerStream = Pin<Box<dyn Stream<Item = InboundServer> + Send +
/// Inbound server configuration.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InboundServer {
pub name: String,
pub reference: ServerRef,
pub protocol: ProxyProtocol,
pub authorizations: HashMap<String, ClientAuthorization>,
pub authorizations: HashMap<AuthorizationRef, ClientAuthorization>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ServerRef {
Default(String),
Server(String),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum AuthorizationRef {
Default(String),
ServerAuthorization(String),
AuthorizationPolicy(String),
}
/// Describes how a proxy should handle inbound connections.
@ -63,7 +77,7 @@ pub enum ClientAuthentication {
/// Indicates that clients need not be authenticated.
Unauthenticated,
/// Indicates that clients must use TLS bu need not provide a client identity.
/// Indicates that clients must use TLS but need not provide a client identity.
TlsUnauthenticated,
/// Indicates that clients must use mutually-authenticated TLS.

View File

@ -15,6 +15,7 @@ drain = "0.1"
futures = { version = "0.3", default-features = false }
linkerd2-proxy-api = { version = "0.3", features = ["inbound", "server"] }
linkerd-policy-controller-core = { path = "../core" }
maplit = "1"
tokio = { version = "1", features = ["macros"] }
tonic = { version = "0.6", default-features = false, features = ["transport"] }
tracing = "0.1"

View File

@ -7,9 +7,11 @@ use linkerd2_proxy_api::inbound::{
inbound_server_policies_server::{InboundServerPolicies, InboundServerPoliciesServer},
};
use linkerd_policy_controller_core::{
ClientAuthentication, ClientAuthorization, DiscoverInboundServer, IdentityMatch, InboundServer,
InboundServerStream, IpNet, NetworkMatch, ProxyProtocol,
AuthorizationRef, ClientAuthentication, ClientAuthorization, DiscoverInboundServer,
IdentityMatch, InboundServer, InboundServerStream, IpNet, NetworkMatch, ProxyProtocol,
ServerRef,
};
use maplit::*;
use std::sync::Arc;
use tracing::trace;
@ -194,9 +196,16 @@ fn to_server(srv: &InboundServer, cluster_networks: &[IpNet]) -> proto::Server {
.collect();
trace!(?authorizations);
let labels = vec![("name".to_string(), srv.name.to_string())]
.into_iter()
.collect();
let labels = match &srv.reference {
ServerRef::Default(name) => convert_args!(hashmap!(
"kind" => "default",
"name" => name,
)),
ServerRef::Server(name) => convert_args!(hashmap!(
"kind" => "server",
"name" => name,
)),
};
trace!(?labels);
proto::Server {
@ -208,7 +217,7 @@ fn to_server(srv: &InboundServer, cluster_networks: &[IpNet]) -> proto::Server {
}
fn to_authz(
name: impl ToString,
reference: &AuthorizationRef,
ClientAuthorization {
networks,
authentication,
@ -233,9 +242,20 @@ fn to_authz(
.collect()
};
let labels = vec![("name".to_string(), name.to_string())]
.into_iter()
.collect();
let labels = match reference {
AuthorizationRef::Default(name) => convert_args!(hashmap!(
"kind" => "default",
"name" => name,
)),
AuthorizationRef::ServerAuthorization(name) => convert_args!(hashmap!(
"kind" => "serverauthorization",
"name" => name,
)),
AuthorizationRef::AuthorizationPolicy(name) => convert_args!(hashmap!(
"kind" => "authorizationpolicy",
"name" => name,
)),
};
let authn = match authentication {
ClientAuthentication::Unauthenticated => proto::Authn {

View File

@ -7,7 +7,9 @@ pub mod policy;
pub use self::labels::Labels;
pub use k8s_openapi::api::{
self,
core::v1::{Namespace, Node, NodeSpec, Pod, PodSpec, PodStatus},
core::v1::{Namespace, Node, NodeSpec, Pod, PodSpec, PodStatus, ServiceAccount},
};
pub use kube::{
api::{ObjectMeta, Resource, ResourceExt},
runtime::watcher::Event as WatchEvent,
};
pub use kube::api::{ObjectMeta, Resource, ResourceExt};
pub use kube::runtime::watcher::Event as WatchEvent;

View File

@ -1,9 +1,17 @@
pub mod network;
pub mod authorization_policy;
pub mod meshtls_authentication;
mod network;
pub mod network_authentication;
pub mod server;
pub mod server_authorization;
pub mod target_ref;
pub use self::{
authorization_policy::{AuthorizationPolicy, AuthorizationPolicySpec},
meshtls_authentication::{MeshTLSAuthentication, MeshTLSAuthenticationSpec},
network::Network,
network_authentication::{NetworkAuthentication, NetworkAuthenticationSpec},
server::{Server, ServerSpec},
server_authorization::{ServerAuthorization, ServerAuthorizationSpec},
target_ref::{ClusterTargetRef, LocalTargetRef, NamespacedTargetRef},
};

View File

@ -0,0 +1,22 @@
use super::{LocalTargetRef, NamespacedTargetRef};
#[derive(
Clone,
Debug,
Default,
kube::CustomResource,
serde::Deserialize,
serde::Serialize,
schemars::JsonSchema,
)]
#[kube(
group = "policy.linkerd.io",
version = "v1alpha1",
kind = "AuthorizationPolicy",
namespaced
)]
#[serde(rename_all = "camelCase")]
pub struct AuthorizationPolicySpec {
pub target_ref: LocalTargetRef,
pub required_authentication_refs: Vec<NamespacedTargetRef>,
}

View File

@ -0,0 +1,23 @@
use super::NamespacedTargetRef;
#[derive(
Clone,
Debug,
Default,
PartialEq,
kube::CustomResource,
serde::Deserialize,
serde::Serialize,
schemars::JsonSchema,
)]
#[kube(
group = "policy.linkerd.io",
version = "v1alpha1",
kind = "MeshTLSAuthentication",
namespaced
)]
#[serde(rename_all = "camelCase")]
pub struct MeshTLSAuthenticationSpec {
pub identities: Option<Vec<String>>,
pub identity_refs: Option<Vec<NamespacedTargetRef>>,
}

View File

@ -0,0 +1,22 @@
pub use super::Network;
#[derive(
Clone,
Debug,
Default,
PartialEq,
kube::CustomResource,
serde::Deserialize,
serde::Serialize,
schemars::JsonSchema,
)]
#[kube(
group = "policy.linkerd.io",
version = "v1alpha1",
kind = "NetworkAuthentication",
namespaced
)]
#[serde(rename_all = "camelCase")]
pub struct NetworkAuthenticationSpec {
pub networks: Vec<Network>,
}

View File

@ -0,0 +1,351 @@
#[derive(
Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
)]
pub struct ClusterTargetRef {
pub group: Option<String>,
pub kind: String,
pub name: String,
}
#[derive(
Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
)]
pub struct LocalTargetRef {
pub group: Option<String>,
pub kind: String,
pub name: String,
}
#[derive(
Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
)]
pub struct NamespacedTargetRef {
pub group: Option<String>,
pub kind: String,
pub name: String,
pub namespace: Option<String>,
}
impl ClusterTargetRef {
pub fn from_resource<T>(resource: &T) -> Self
where
T: kube::Resource,
T::DynamicType: Default,
{
let (group, kind, name) = group_kind_name(resource);
Self { group, kind, name }
}
/// Returns the target ref kind, qualified by its group, if necessary.
pub fn canonical_kind(&self) -> String {
canonical_kind(self.group.as_deref(), &self.kind)
}
/// Checks whether the target references the given resource type
pub fn targets_kind<T>(&self) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
targets_kind::<T>(self.group.as_deref(), &self.kind)
}
/// Checks whether the target references the given cluster-level resource
pub fn targets<T>(&self, resource: &T) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
if !self.targets_kind::<T>() {
return false;
}
if resource.meta().namespace.is_some() {
// If the reference or the resource has a namespace, that's a deal-breaker.
return false;
}
match resource.meta().name.as_deref() {
None => return false,
Some(rname) => {
if !self.name.eq_ignore_ascii_case(rname) {
return false;
}
}
}
true
}
}
impl LocalTargetRef {
pub fn from_resource<T>(resource: &T) -> Self
where
T: kube::Resource,
T::DynamicType: Default,
{
let (group, kind, name) = group_kind_name(resource);
Self { group, kind, name }
}
/// Returns the target ref kind, qualified by its group, if necessary.
pub fn canonical_kind(&self) -> String {
canonical_kind(self.group.as_deref(), &self.kind)
}
/// Checks whether the target references the given resource type
pub fn targets_kind<T>(&self) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
targets_kind::<T>(self.group.as_deref(), &self.kind)
}
/// Checks whether the target references the given namespaced resource
pub fn targets<T>(&self, resource: &T, local_ns: &str) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
if !self.targets_kind::<T>() {
return false;
}
// If the resource specifies a namespace other than the target or the
// default namespace, that's a deal-breaker.
match resource.meta().namespace.as_deref() {
Some(rns) if rns.eq_ignore_ascii_case(local_ns) => {}
_ => return false,
};
match resource.meta().name.as_deref() {
Some(rname) => rname.eq_ignore_ascii_case(&self.name),
_ => false,
}
}
}
impl NamespacedTargetRef {
pub fn from_resource<T>(resource: &T) -> Self
where
T: kube::Resource,
T::DynamicType: Default,
{
let (group, kind, name) = group_kind_name(resource);
let namespace = resource.meta().namespace.clone();
Self {
group,
kind,
name,
namespace,
}
}
/// Returns the target ref kind, qualified by its group, if necessary.
pub fn canonical_kind(&self) -> String {
canonical_kind(self.group.as_deref(), &self.kind)
}
/// Checks whether the target references the given resource type
pub fn targets_kind<T>(&self) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
targets_kind::<T>(self.group.as_deref(), &self.kind)
}
/// Checks whether the target references the given namespaced resource
pub fn targets<T>(&self, resource: &T, local_ns: &str) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
if !self.targets_kind::<T>() {
return false;
}
// If the resource specifies a namespace other than the target or the
// default namespace, that's a deal-breaker.
let tns = self.namespace.as_deref().unwrap_or(local_ns);
match resource.meta().namespace.as_deref() {
Some(rns) if rns.eq_ignore_ascii_case(tns) => {}
_ => return false,
};
match resource.meta().name.as_deref() {
None => return false,
Some(rname) => {
if !self.name.eq_ignore_ascii_case(rname) {
return false;
}
}
}
true
}
}
fn canonical_kind(group: Option<&str>, kind: &str) -> String {
if let Some(group) = group {
format!("{}.{}", kind, group)
} else {
kind.to_string()
}
}
fn targets_kind<T>(group: Option<&str>, kind: &str) -> bool
where
T: kube::Resource,
T::DynamicType: Default,
{
let dt = Default::default();
let mut t_group = &*T::group(&dt);
if t_group.is_empty() {
t_group = "core";
}
group.unwrap_or("core").eq_ignore_ascii_case(t_group)
&& kind.eq_ignore_ascii_case(&*T::kind(&dt))
}
fn group_kind_name<T>(resource: &T) -> (Option<String>, String, String)
where
T: kube::Resource,
T::DynamicType: Default,
{
let dt = Default::default();
let group = match T::group(&dt) {
g if (*g).is_empty() => None,
g => Some(g.to_string()),
};
let kind = T::kind(&dt).to_string();
let name = resource
.meta()
.name
.clone()
.expect("resource must have a name");
(group, kind, name)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{policy::Server, Namespace, ObjectMeta, ServiceAccount};
#[test]
fn cluster_targets_namespace() {
let t = ClusterTargetRef {
kind: "Namespace".to_string(),
name: "appns".to_string(),
..Default::default()
};
assert!(t.targets_kind::<Namespace>());
assert!(t.targets(&Namespace {
metadata: ObjectMeta {
name: Some("appns".to_string()),
..ObjectMeta::default()
},
..Namespace::default()
}));
}
#[test]
fn namespaced_targets_service_account() {
for tgt in &[
NamespacedTargetRef {
kind: "ServiceAccount".to_string(),
name: "default".to_string(),
namespace: Some("appns".to_string()),
..Default::default()
},
NamespacedTargetRef {
group: Some("core".to_string()),
kind: "ServiceAccount".to_string(),
name: "default".to_string(),
namespace: Some("appns".to_string()),
},
NamespacedTargetRef {
group: Some("CORE".to_string()),
kind: "SERVICEACCOUNT".to_string(),
name: "DEFAULT".to_string(),
namespace: Some("APPNS".to_string()),
},
NamespacedTargetRef {
kind: "ServiceAccount".to_string(),
name: "default".to_string(),
..Default::default()
},
] {
assert!(tgt.targets_kind::<ServiceAccount>());
assert!(!tgt.targets_kind::<Namespace>());
let sa = ServiceAccount {
metadata: ObjectMeta {
namespace: Some("appns".to_string()),
name: Some("default".to_string()),
..ObjectMeta::default()
},
..ServiceAccount::default()
};
assert!(
tgt.targets(&sa, "appns"),
"ServiceAccounts are targeted by name: {:#?}",
tgt
);
let sa = ServiceAccount {
metadata: ObjectMeta {
namespace: Some("otherns".to_string()),
name: Some("default".to_string()),
..ObjectMeta::default()
},
..ServiceAccount::default()
};
assert!(
!tgt.targets(&sa, "appns"),
"ServiceAccounts in other namespaces should not be targeted: {:#?}",
tgt
);
}
let tgt = NamespacedTargetRef {
kind: "ServiceAccount".to_string(),
name: "default".to_string(),
..Default::default()
};
assert!(
{
let sa = ServiceAccount {
metadata: ObjectMeta {
namespace: Some("appns".to_string()),
name: Some("special".to_string()),
..ObjectMeta::default()
},
..ServiceAccount::default()
};
!tgt.targets(&sa, "appns")
},
"resource comparison uses "
);
}
#[test]
fn namespaced_targets_server() {
let tgt = NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "http".to_string(),
namespace: Some("appns".to_string()),
};
assert!(tgt.targets_kind::<Server>());
}
}

View File

@ -17,6 +17,7 @@ tokio = { version = "1", features = ["macros", "rt", "sync"] }
tracing = "0.1"
[dev-dependencies]
maplit = "1"
tokio-stream = "0.1"
tokio-test = "0.4"
tracing-subscriber = "0.3"

View File

@ -0,0 +1,85 @@
use anyhow::{bail, Result};
use linkerd_policy_controller_k8s_api::{
self as k8s,
policy::{LocalTargetRef, NamespacedTargetRef},
};
#[derive(Debug, PartialEq)]
pub(crate) struct Spec {
pub target: Target,
pub authentications: Vec<AuthenticationTarget>,
}
#[derive(Debug, PartialEq)]
pub(crate) enum Target {
Server(String),
}
#[derive(Debug, PartialEq)]
pub(crate) enum AuthenticationTarget {
MeshTLS {
namespace: Option<String>,
name: String,
},
Network {
namespace: Option<String>,
name: String,
},
}
impl TryFrom<k8s::policy::AuthorizationPolicySpec> for Spec {
type Error = anyhow::Error;
fn try_from(ap: k8s::policy::AuthorizationPolicySpec) -> Result<Self> {
let target = target(ap.target_ref)?;
let authentications = ap
.required_authentication_refs
.into_iter()
.map(authentication_ref)
.collect::<Result<Vec<_>>>()?;
if authentications.is_empty() {
bail!("No authentication targets");
}
Ok(Self {
target,
authentications,
})
}
}
impl Target {
pub(crate) fn server(&self) -> Option<&str> {
match self {
Self::Server(s) => Some(s),
}
}
}
fn target(t: LocalTargetRef) -> Result<Target> {
if t.targets_kind::<k8s::policy::Server>() {
return Ok(Target::Server(t.name));
}
anyhow::bail!(
"unsupported authorization target type: {}",
t.canonical_kind()
);
}
fn authentication_ref(t: NamespacedTargetRef) -> Result<AuthenticationTarget> {
if t.targets_kind::<k8s::policy::MeshTLSAuthentication>() {
Ok(AuthenticationTarget::MeshTLS {
namespace: t.namespace.map(Into::into),
name: t.name,
})
} else if t.targets_kind::<k8s::policy::NetworkAuthentication>() {
Ok(AuthenticationTarget::Network {
namespace: t.namespace.map(Into::into),
name: t.name,
})
} else {
anyhow::bail!("unsupported authentication target: {}", t.canonical_kind());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -23,8 +23,11 @@
#![deny(warnings, rust_2018_idioms)]
#![forbid(unsafe_code)]
mod authorization_policy;
mod defaults;
mod index;
mod meshtls_authentication;
mod network_authentication;
mod pod;
mod server;
mod server_authorization;

View File

@ -0,0 +1,46 @@
use crate::ClusterInfo;
use anyhow::Result;
use linkerd_policy_controller_core::IdentityMatch;
use linkerd_policy_controller_k8s_api::{
policy::MeshTLSAuthentication, ResourceExt, ServiceAccount,
};
#[derive(Debug, PartialEq)]
pub(crate) struct Spec {
pub matches: Vec<IdentityMatch>,
}
impl Spec {
pub(crate) fn try_from_resource(
ma: MeshTLSAuthentication,
cluster: &ClusterInfo,
) -> anyhow::Result<Self> {
let namespace = ma
.namespace()
.expect("MeshTLSAuthentication must have a namespace");
let identities = ma.spec.identities.into_iter().flatten().map(|s| {
Ok(s.parse::<IdentityMatch>()
.expect("identity match parsing is infallible"))
});
let identity_refs = ma.spec.identity_refs.into_iter().flatten().map(|tgt| {
if tgt.targets_kind::<ServiceAccount>() {
let ns = tgt.namespace.as_deref().unwrap_or(&namespace);
let id = cluster.service_account_identity(ns, &tgt.name);
Ok(IdentityMatch::Exact(id))
} else {
anyhow::bail!("unsupported target type: {:?}", tgt.canonical_kind())
}
});
let matches = identities
.chain(identity_refs)
.collect::<Result<Vec<_>>>()?;
if matches.is_empty() {
anyhow::bail!("No identities configured");
}
Ok(Spec { matches })
}
}

View File

@ -0,0 +1,28 @@
use linkerd_policy_controller_core::NetworkMatch;
use linkerd_policy_controller_k8s_api::policy::NetworkAuthenticationSpec;
#[derive(Debug, PartialEq)]
pub(crate) struct Spec {
pub matches: Vec<NetworkMatch>,
}
impl TryFrom<NetworkAuthenticationSpec> for Spec {
type Error = anyhow::Error;
fn try_from(spec: NetworkAuthenticationSpec) -> anyhow::Result<Self> {
let matches = spec
.networks
.into_iter()
.map(|n| NetworkMatch {
net: n.cidr.into(),
except: n.except.into_iter().flatten().map(Into::into).collect(),
})
.collect::<Vec<_>>();
if matches.is_empty() {
anyhow::bail!("No networks configured");
}
Ok(Spec { matches })
}
}

View File

@ -1,13 +1,21 @@
mod annotation;
mod authorization_policy;
mod server_authorization;
use crate::{defaults::DefaultPolicy, index::*, server_authorization::ServerSelector, ClusterInfo};
use ahash::AHashMap as HashMap;
use kubert::index::IndexNamespacedResource;
use linkerd_policy_controller_core::{
ClientAuthentication, ClientAuthorization, IdentityMatch, InboundServer, IpNet, Ipv4Net,
Ipv6Net, NetworkMatch, ProxyProtocol,
AuthorizationRef, ClientAuthentication, ClientAuthorization, IdentityMatch, InboundServer,
IpNet, Ipv4Net, Ipv6Net, NetworkMatch, ProxyProtocol, ServerRef,
};
use linkerd_policy_controller_k8s_api::{
self as k8s, api::core::v1::ContainerPort, policy::server::Port, ResourceExt,
self as k8s,
api::core::v1::ContainerPort,
policy::{server::Port, LocalTargetRef, NamespacedTargetRef},
ResourceExt,
};
use maplit::*;
use tokio::time;
#[test]
@ -19,329 +27,14 @@ fn pod_must_exist_for_lookup() {
.expect_err("pod-0.ns-0 must not exist");
}
#[test]
fn links_named_server_port() {
let test = TestConfig::default();
let mut pod = mk_pod(
"ns-0",
"pod-0",
Some((
"container-0",
Some(ContainerPort {
name: Some("admin-http".to_string()),
container_port: 8080,
protocol: Some("TCP".to_string()),
..ContainerPort::default()
}),
)),
);
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-admin-http",
Port::Name("admin-http".to_string()),
None,
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
name: "srv-admin-http".to_string(),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
struct TestConfig {
index: SharedIndex,
detect_timeout: time::Duration,
default_policy: DefaultPolicy,
cluster: ClusterInfo,
_tracing: tracing::subscriber::DefaultGuard,
}
#[test]
fn links_unnamed_server_port() {
let test = TestConfig::default();
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-8080",
Port::Number(8080),
None,
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
name: "srv-8080".to_string(),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
}
#[test]
fn links_server_authz_by_name() {
link_server_authz(ServerSelector::Name("srv-8080".to_string()))
}
#[test]
fn links_server_authz_by_label() {
link_server_authz(ServerSelector::Selector(
Some(("app", "app-0")).into_iter().collect(),
));
}
#[inline]
fn link_server_authz(selector: ServerSelector) {
let test = TestConfig::default();
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-8080",
Port::Number(8080),
Some(("app", "app-0")),
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
name: "srv-8080".to_string(),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
test.index.write().apply(mk_server_authz(
"ns-0",
"authz-foo",
selector,
k8s::policy::server_authorization::Client {
networks: Some(vec![k8s::policy::server_authorization::Network {
cidr: "10.0.0.0/8".parse().unwrap(),
except: None,
}]),
unauthenticated: false,
mesh_tls: Some(k8s::policy::server_authorization::MeshTls {
identities: Some(vec!["foo.bar".to_string()]),
..Default::default()
}),
},
));
assert!(rx.has_changed().unwrap());
assert_eq!(rx.borrow().name, "srv-8080");
assert_eq!(rx.borrow().protocol, ProxyProtocol::Http1,);
assert!(rx.borrow().authorizations.contains_key("authz-foo"));
}
#[test]
fn server_update_deselects_pod() {
let test = TestConfig::default();
test.index.write().reset(
vec![mk_pod("ns-0", "pod-0", Some(("container-0", None)))],
Default::default(),
);
let mut srv = mk_server(
"ns-0",
"srv-0",
Port::Number(2222),
None,
None,
Some(k8s::policy::server::ProxyProtocol::Http2),
);
test.index
.write()
.reset(vec![srv.clone()], Default::default());
// The default policy applies for all ports.
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.unwrap();
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
name: "srv-0".into(),
protocol: ProxyProtocol::Http2,
authorizations: Default::default(),
}
);
test.index.write().apply({
srv.spec.pod_selector = Some(("label", "value")).into_iter().collect();
srv
});
assert!(rx.has_changed().unwrap());
assert_eq!(*rx.borrow(), test.default_server());
}
/// Tests that pod servers are configured with defaults based on the
/// workload-defined `DefaultPolicy` policy.
///
/// Iterates through each default policy and validates that it produces expected
/// configurations.
#[test]
fn default_policy_annotated() {
for default in &DEFAULTS {
let test = TestConfig::from_default_policy(match *default {
// Invert default to ensure override applies.
DefaultPolicy::Deny => DefaultPolicy::Allow {
authenticated_only: false,
cluster_only: false,
},
_ => DefaultPolicy::Deny,
});
// Initially create the pod without an annotation and check that it gets
// the global default.
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
test.index
.write()
.reset(vec![pod.clone()], Default::default());
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod-0.ns-0 should exist");
assert_eq!(
rx.borrow_and_update().name,
format!("default:{}", test.default_policy)
);
// Update the annotation on the pod and check that the watch is updated
// with the new default.
pod.annotations_mut().insert(
"config.linkerd.io/default-inbound-policy".into(),
default.to_string(),
);
test.index.write().apply(pod);
assert!(rx.has_changed().unwrap());
assert_eq!(rx.borrow().name, format!("default:{}", default));
}
}
/// Tests that an invalid workload annotation is ignored in favor of the global
/// default.
#[tokio::test]
async fn default_policy_annotated_invalid() {
let test = TestConfig::default();
let mut p = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
p.annotations_mut().insert(
"config.linkerd.io/default-inbound-policy".into(),
"bogus".into(),
);
test.index.write().reset(vec![p], Default::default());
// Lookup port 2222 -> default config.
let rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod must exist in lookups");
assert_eq!(*rx.borrow(), test.default_server());
}
#[test]
fn opaque_annotated() {
for default in &DEFAULTS {
let test = TestConfig::from_default_policy(*default);
let mut p = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
p.annotations_mut()
.insert("config.linkerd.io/opaque-ports".into(), "2222".into());
test.index.write().reset(vec![p], Default::default());
let mut server = test.default_server();
server.protocol = ProxyProtocol::Opaque;
let rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow(), server);
}
}
#[test]
fn authenticated_annotated() {
for default in &DEFAULTS {
let test = TestConfig::from_default_policy(*default);
let mut p = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
p.annotations_mut().insert(
"config.linkerd.io/proxy-require-identity-inbound-ports".into(),
"2222".into(),
);
test.index.write().reset(vec![p], Default::default());
let config = {
let policy = match *default {
DefaultPolicy::Allow { cluster_only, .. } => DefaultPolicy::Allow {
cluster_only,
authenticated_only: true,
},
DefaultPolicy::Deny => DefaultPolicy::Deny,
};
InboundServer {
name: format!("default:{}", policy),
authorizations: mk_default_policy(policy, test.cluster.networks),
protocol: ProxyProtocol::Detect {
timeout: test.detect_timeout,
},
}
};
let rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow(), config);
}
}
// === Helpers ===
const DEFAULTS: [DefaultPolicy; 5] = [
DefaultPolicy::Deny,
DefaultPolicy::Allow {
@ -363,21 +56,21 @@ const DEFAULTS: [DefaultPolicy; 5] = [
];
fn mk_pod(
ns: impl Into<String>,
name: impl Into<String>,
containers: impl IntoIterator<Item = (impl Into<String>, impl IntoIterator<Item = ContainerPort>)>,
ns: impl ToString,
name: impl ToString,
containers: impl IntoIterator<Item = (impl ToString, impl IntoIterator<Item = ContainerPort>)>,
) -> k8s::Pod {
k8s::Pod {
metadata: k8s::ObjectMeta {
namespace: Some(ns.into()),
name: Some(name.into()),
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
..Default::default()
},
spec: Some(k8s::api::core::v1::PodSpec {
containers: containers
.into_iter()
.map(|(name, ports)| k8s::api::core::v1::Container {
name: name.into(),
name: name.to_string(),
ports: Some(ports.into_iter().collect()),
..Default::default()
})
@ -389,8 +82,8 @@ fn mk_pod(
}
fn mk_server(
ns: impl Into<String>,
name: impl Into<String>,
ns: impl ToString,
name: impl ToString,
port: Port,
srv_labels: impl IntoIterator<Item = (&'static str, &'static str)>,
pod_labels: impl IntoIterator<Item = (&'static str, &'static str)>,
@ -398,8 +91,8 @@ fn mk_server(
) -> k8s::policy::Server {
k8s::policy::Server {
metadata: k8s::ObjectMeta {
namespace: Some(ns.into()),
name: Some(name.into()),
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
labels: Some(
srv_labels
.into_iter()
@ -416,38 +109,10 @@ fn mk_server(
}
}
fn mk_server_authz(
ns: impl Into<String>,
name: impl Into<String>,
selector: ServerSelector,
client: k8s::policy::server_authorization::Client,
) -> k8s::policy::ServerAuthorization {
k8s::policy::ServerAuthorization {
metadata: k8s::ObjectMeta {
namespace: Some(ns.into()),
name: Some(name.into()),
..Default::default()
},
spec: k8s::policy::ServerAuthorizationSpec {
server: match selector {
ServerSelector::Name(n) => k8s::policy::server_authorization::Server {
name: Some(n),
selector: None,
},
ServerSelector::Selector(s) => k8s::policy::server_authorization::Server {
selector: Some(s),
name: None,
},
},
client,
},
}
}
fn mk_default_policy(
da: DefaultPolicy,
cluster_nets: Vec<IpNet>,
) -> HashMap<String, ClientAuthorization> {
) -> HashMap<AuthorizationRef, ClientAuthorization> {
let all_nets = vec![Ipv4Net::default().into(), Ipv6Net::default().into()];
let cluster_nets = cluster_nets.into_iter().map(NetworkMatch::from).collect();
@ -460,7 +125,7 @@ fn mk_default_policy(
authenticated_only: true,
cluster_only: false,
} => Some((
"default:all-authenticated".into(),
AuthorizationRef::Default("all-authenticated".to_string()),
ClientAuthorization {
authentication: authed,
networks: all_nets,
@ -470,7 +135,7 @@ fn mk_default_policy(
authenticated_only: false,
cluster_only: false,
} => Some((
"default:all-unauthenticated".into(),
AuthorizationRef::Default("all-unauthenticated".to_string()),
ClientAuthorization {
authentication: ClientAuthentication::Unauthenticated,
networks: all_nets,
@ -480,7 +145,7 @@ fn mk_default_policy(
authenticated_only: true,
cluster_only: true,
} => Some((
"default:cluster-authenticated".into(),
AuthorizationRef::Default("cluster-authenticated".to_string()),
ClientAuthorization {
authentication: authed,
networks: cluster_nets,
@ -490,7 +155,7 @@ fn mk_default_policy(
authenticated_only: false,
cluster_only: true,
} => Some((
"default:cluster-unauthenticated".into(),
AuthorizationRef::Default("cluster-unauthenticated".to_string()),
ClientAuthorization {
authentication: ClientAuthentication::Unauthenticated,
networks: cluster_nets,
@ -501,14 +166,6 @@ fn mk_default_policy(
.collect()
}
struct TestConfig {
index: SharedIndex,
detect_timeout: time::Duration,
default_policy: DefaultPolicy,
cluster: ClusterInfo,
_tracing: tracing::subscriber::DefaultGuard,
}
impl TestConfig {
fn from_default_policy(default_policy: DefaultPolicy) -> Self {
let _tracing = Self::init_tracing();
@ -533,7 +190,7 @@ impl TestConfig {
fn default_server(&self) -> InboundServer {
InboundServer {
name: format!("default:{}", self.default_policy),
reference: ServerRef::Default(self.default_policy.to_string()),
authorizations: mk_default_policy(self.default_policy, self.cluster.networks.clone()),
protocol: ProxyProtocol::Detect {
timeout: self.detect_timeout,

View File

@ -0,0 +1,132 @@
use super::*;
/// Tests that pod servers are configured with defaults based on the
/// workload-defined `DefaultPolicy` policy.
///
/// Iterates through each default policy and validates that it produces expected
/// configurations.
#[test]
fn default_policy_annotated() {
for default in &DEFAULTS {
let test = TestConfig::from_default_policy(match *default {
// Invert default to ensure override applies.
DefaultPolicy::Deny => DefaultPolicy::Allow {
authenticated_only: false,
cluster_only: false,
},
_ => DefaultPolicy::Deny,
});
// Initially create the pod without an annotation and check that it gets
// the global default.
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
test.index
.write()
.reset(vec![pod.clone()], Default::default());
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod-0.ns-0 should exist");
assert_eq!(
rx.borrow_and_update().reference,
ServerRef::Default(test.default_policy.to_string()),
);
// Update the annotation on the pod and check that the watch is updated
// with the new default.
pod.annotations_mut().insert(
"config.linkerd.io/default-inbound-policy".into(),
default.to_string(),
);
test.index.write().apply(pod);
assert!(rx.has_changed().unwrap());
assert_eq!(
rx.borrow().reference,
ServerRef::Default(default.to_string())
);
}
}
/// Tests that an invalid workload annotation is ignored in favor of the global
/// default.
#[tokio::test]
async fn default_policy_annotated_invalid() {
let test = TestConfig::default();
let mut p = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
p.annotations_mut().insert(
"config.linkerd.io/default-inbound-policy".into(),
"bogus".into(),
);
test.index.write().reset(vec![p], Default::default());
// Lookup port 2222 -> default config.
let rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod must exist in lookups");
assert_eq!(*rx.borrow(), test.default_server());
}
#[test]
fn opaque_annotated() {
for default in &DEFAULTS {
let test = TestConfig::from_default_policy(*default);
let mut p = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
p.annotations_mut()
.insert("config.linkerd.io/opaque-ports".into(), "2222".into());
test.index.write().reset(vec![p], Default::default());
let mut server = test.default_server();
server.protocol = ProxyProtocol::Opaque;
let rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow(), server);
}
}
#[test]
fn authenticated_annotated() {
for default in &DEFAULTS {
let test = TestConfig::from_default_policy(*default);
let mut p = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
p.annotations_mut().insert(
"config.linkerd.io/proxy-require-identity-inbound-ports".into(),
"2222".into(),
);
test.index.write().reset(vec![p], Default::default());
let config = {
let policy = match *default {
DefaultPolicy::Allow { cluster_only, .. } => DefaultPolicy::Allow {
cluster_only,
authenticated_only: true,
},
DefaultPolicy::Deny => DefaultPolicy::Deny,
};
InboundServer {
reference: ServerRef::Default(policy.to_string()),
authorizations: mk_default_policy(policy, test.cluster.networks),
protocol: ProxyProtocol::Detect {
timeout: test.detect_timeout,
},
}
};
let rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow(), config);
}
}

View File

@ -0,0 +1,158 @@
use super::*;
#[test]
fn links_authorization_policy_with_mtls_name() {
let test = TestConfig::default();
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-8080",
Port::Number(8080),
None,
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
reference: ServerRef::Server("srv-8080".to_string()),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
let authz = ClientAuthorization {
networks: vec!["10.0.0.0/8".parse::<IpNet>().unwrap().into()],
authentication: ClientAuthentication::TlsAuthenticated(vec![IdentityMatch::Exact(
"foo.bar".to_string(),
)]),
};
test.index.write().apply(mk_authorization_policy(
"ns-0",
"authz-foo",
"srv-8080",
vec![
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "NetworkAuthentication".to_string(),
name: "net-foo".to_string(),
..Default::default()
},
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "MeshTLSAuthentication".to_string(),
namespace: Some("ns-1".to_string()),
name: "mtls-bar".to_string(),
},
],
));
test.index.write().apply(mk_network_authentication(
"ns-0".to_string(),
"net-foo".to_string(),
vec![k8s::policy::network_authentication::Network {
cidr: "10.0.0.0/8".parse().unwrap(),
except: None,
}],
));
test.index.write().apply(mk_meshtls_authentication(
"ns-1",
"mtls-bar",
Some("foo.bar".to_string()),
None,
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow(),
InboundServer {
reference: ServerRef::Server("srv-8080".to_string()),
authorizations: hashmap!(
AuthorizationRef::AuthorizationPolicy("authz-foo".to_string()) => authz
)
.into_iter()
.collect(),
protocol: ProxyProtocol::Http1,
},
);
}
fn mk_authorization_policy(
ns: impl ToString,
name: impl ToString,
server: impl ToString,
authns: impl IntoIterator<Item = NamespacedTargetRef>,
) -> k8s::policy::AuthorizationPolicy {
k8s::policy::AuthorizationPolicy {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
..Default::default()
},
spec: k8s::policy::AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: server.to_string(),
},
required_authentication_refs: authns.into_iter().collect(),
},
}
}
fn mk_meshtls_authentication(
ns: impl ToString,
name: impl ToString,
identities: impl IntoIterator<Item = String>,
refs: impl IntoIterator<Item = NamespacedTargetRef>,
) -> k8s::policy::MeshTLSAuthentication {
let identities = identities.into_iter().collect::<Vec<_>>();
let identity_refs = refs.into_iter().collect::<Vec<_>>();
k8s::policy::MeshTLSAuthentication {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
..Default::default()
},
spec: k8s::policy::MeshTLSAuthenticationSpec {
identities: if identities.is_empty() {
None
} else {
Some(identities)
},
identity_refs: if identity_refs.is_empty() {
None
} else {
Some(identity_refs)
},
},
}
}
fn mk_network_authentication(
ns: impl ToString,
name: impl ToString,
networks: impl IntoIterator<Item = k8s::policy::network_authentication::Network>,
) -> k8s::policy::NetworkAuthentication {
k8s::policy::NetworkAuthentication {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
..Default::default()
},
spec: k8s::policy::NetworkAuthenticationSpec {
networks: networks.into_iter().collect(),
},
}
}

View File

@ -0,0 +1,127 @@
use super::*;
#[test]
fn links_named_server_port() {
let test = TestConfig::default();
let mut pod = mk_pod(
"ns-0",
"pod-0",
Some((
"container-0",
Some(ContainerPort {
name: Some("admin-http".to_string()),
container_port: 8080,
protocol: Some("TCP".to_string()),
..ContainerPort::default()
}),
)),
);
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-admin-http",
Port::Name("admin-http".to_string()),
None,
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
reference: ServerRef::Server("srv-admin-http".to_string()),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
}
#[test]
fn links_unnamed_server_port() {
let test = TestConfig::default();
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-8080",
Port::Number(8080),
None,
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
reference: ServerRef::Server("srv-8080".to_string()),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
}
#[test]
fn server_update_deselects_pod() {
let test = TestConfig::default();
test.index.write().reset(
vec![mk_pod("ns-0", "pod-0", Some(("container-0", None)))],
Default::default(),
);
let mut srv = mk_server(
"ns-0",
"srv-0",
Port::Number(2222),
None,
None,
Some(k8s::policy::server::ProxyProtocol::Http2),
);
test.index
.write()
.reset(vec![srv.clone()], Default::default());
// The default policy applies for all ports.
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 2222)
.unwrap();
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
reference: ServerRef::Server("srv-0".to_string()),
protocol: ProxyProtocol::Http2,
authorizations: Default::default(),
}
);
test.index.write().apply({
srv.spec.pod_selector = Some(("label", "value")).into_iter().collect();
srv
});
assert!(rx.has_changed().unwrap());
assert_eq!(*rx.borrow(), test.default_server());
}

View File

@ -0,0 +1,104 @@
use super::*;
#[test]
fn links_server_authz_by_name() {
link_server_authz(ServerSelector::Name("srv-8080".to_string()))
}
#[test]
fn links_server_authz_by_label() {
link_server_authz(ServerSelector::Selector(
Some(("app", "app-0")).into_iter().collect(),
));
}
#[inline]
fn link_server_authz(selector: ServerSelector) {
let test = TestConfig::default();
let mut pod = mk_pod("ns-0", "pod-0", Some(("container-0", None)));
pod.labels_mut()
.insert("app".to_string(), "app-0".to_string());
test.index.write().apply(pod);
let mut rx = test
.index
.write()
.pod_server_rx("ns-0", "pod-0", 8080)
.expect("pod-0.ns-0 should exist");
assert_eq!(*rx.borrow_and_update(), test.default_server());
test.index.write().apply(mk_server(
"ns-0",
"srv-8080",
Port::Number(8080),
Some(("app", "app-0")),
Some(("app", "app-0")),
Some(k8s::policy::server::ProxyProtocol::Http1),
));
assert!(rx.has_changed().unwrap());
assert_eq!(
*rx.borrow_and_update(),
InboundServer {
reference: ServerRef::Server("srv-8080".to_string()),
authorizations: Default::default(),
protocol: ProxyProtocol::Http1,
},
);
test.index.write().apply(mk_server_authz(
"ns-0",
"authz-foo",
selector,
k8s::policy::server_authorization::Client {
networks: Some(vec![k8s::policy::server_authorization::Network {
cidr: "10.0.0.0/8".parse().unwrap(),
except: None,
}]),
unauthenticated: false,
mesh_tls: Some(k8s::policy::server_authorization::MeshTls {
identities: Some(vec!["foo.bar".to_string()]),
..Default::default()
}),
},
));
assert!(rx.has_changed().unwrap());
assert_eq!(
rx.borrow().reference,
ServerRef::Server("srv-8080".to_string())
);
assert_eq!(rx.borrow().protocol, ProxyProtocol::Http1,);
assert!(rx
.borrow()
.authorizations
.contains_key(&AuthorizationRef::ServerAuthorization(
"authz-foo".to_string()
)));
}
fn mk_server_authz(
ns: impl ToString,
name: impl ToString,
selector: ServerSelector,
client: k8s::policy::server_authorization::Client,
) -> k8s::policy::ServerAuthorization {
k8s::policy::ServerAuthorization {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
..Default::default()
},
spec: k8s::policy::ServerAuthorizationSpec {
server: match selector {
ServerSelector::Name(n) => k8s::policy::server_authorization::Server {
name: Some(n),
selector: None,
},
ServerSelector::Selector(s) => k8s::policy::server_authorization::Server {
selector: Some(s),
name: None,
},
},
client,
},
}
}

View File

@ -1,10 +1,15 @@
use crate::k8s::{
labels,
policy::{Server, ServerAuthorization, ServerAuthorizationSpec, ServerSpec},
policy::{
AuthorizationPolicy, AuthorizationPolicySpec, MeshTLSAuthentication,
MeshTLSAuthenticationSpec, NetworkAuthentication, NetworkAuthenticationSpec, Server,
ServerAuthorization, ServerAuthorizationSpec, ServerSpec,
},
};
use anyhow::{anyhow, bail, Result};
use futures::future;
use hyper::{body::Buf, http, Body, Request, Response};
use k8s_openapi::api::core::v1::ServiceAccount;
use kube::{core::DynamicObject, Resource, ResourceExt};
use serde::de::DeserializeOwned;
use std::task;
@ -91,6 +96,18 @@ impl Admission {
}
async fn admit(self, req: AdmissionRequest) -> AdmissionResponse {
if is_kind::<AuthorizationPolicy>(&req) {
return self.admit_spec::<AuthorizationPolicySpec>(req).await;
}
if is_kind::<MeshTLSAuthentication>(&req) {
return self.admit_spec::<MeshTLSAuthenticationSpec>(req).await;
}
if is_kind::<NetworkAuthentication>(&req) {
return self.admit_spec::<NetworkAuthenticationSpec>(req).await;
}
if is_kind::<Server>(&req) {
return self.admit_spec::<ServerSpec>(req).await;
};
@ -170,6 +187,71 @@ fn parse_spec<T: DeserializeOwned>(req: AdmissionRequest) -> Result<(String, Str
Ok((ns, name, spec))
}
#[async_trait::async_trait]
impl Validate<AuthorizationPolicySpec> for Admission {
async fn validate(self, _ns: &str, _name: &str, spec: AuthorizationPolicySpec) -> Result<()> {
// TODO support namespace references?
if !spec.target_ref.targets_kind::<Server>() {
bail!(
"invalid targetRef kind: {}",
spec.target_ref.canonical_kind()
);
}
let mtls_authns_count = spec
.required_authentication_refs
.iter()
.filter(|authn| authn.targets_kind::<MeshTLSAuthentication>())
.count();
if mtls_authns_count > 1 {
bail!("only a single MeshTLSAuthentication may be set");
}
let net_authns_count = spec
.required_authentication_refs
.iter()
.filter(|authn| authn.targets_kind::<NetworkAuthentication>())
.count();
if net_authns_count > 1 {
bail!("only a single NetworkAuthentication may be set");
}
if mtls_authns_count + net_authns_count < spec.required_authentication_refs.len() {
let kinds = spec
.required_authentication_refs
.iter()
.filter(|authn| {
!authn.targets_kind::<MeshTLSAuthentication>()
&& !authn.targets_kind::<NetworkAuthentication>()
})
.map(|authn| authn.canonical_kind())
.collect::<Vec<_>>();
bail!("unsupported authentication kind(s): {}", kinds.join(", "));
}
if mtls_authns_count + net_authns_count == 0 {
bail!("at least one authentication reference must be set");
}
Ok(())
}
}
#[async_trait::async_trait]
impl Validate<MeshTLSAuthenticationSpec> for Admission {
async fn validate(self, _ns: &str, _name: &str, spec: MeshTLSAuthenticationSpec) -> Result<()> {
// The CRD validates identity strings, but does not validate identity references.
for id in spec.identity_refs.iter().flatten() {
if !id.targets_kind::<ServiceAccount>() {
bail!("invalid identity target kind: {}", id.canonical_kind());
}
}
Ok(())
}
}
#[async_trait::async_trait]
impl Validate<ServerSpec> for Admission {
/// Checks that `spec` doesn't select the same pod/ports as other existing Servers
@ -212,6 +294,35 @@ impl Admission {
}
}
#[async_trait::async_trait]
impl Validate<NetworkAuthenticationSpec> for Admission {
async fn validate(self, _ns: &str, _name: &str, spec: NetworkAuthenticationSpec) -> Result<()> {
if spec.networks.is_empty() {
bail!("at least one network must be specified");
}
for net in spec.networks.into_iter() {
for except in net.except.into_iter().flatten() {
if except.contains(&net.cidr) {
bail!(
"cidr '{}' is completely negated by exception '{}'",
net.cidr,
except
);
}
if !net.cidr.contains(&except) {
bail!(
"cidr '{}' does not include exception '{}'",
net.cidr,
except
);
}
}
}
Ok(())
}
}
#[async_trait::async_trait]
impl Validate<ServerAuthorizationSpec> for Admission {
async fn validate(self, _ns: &str, _name: &str, spec: ServerAuthorizationSpec) -> Result<()> {

View File

@ -125,6 +125,27 @@ async fn main() -> Result<()> {
.instrument(info_span!("serverauthorizations")),
);
let authz_policies =
runtime.watch_all::<k8s::policy::AuthorizationPolicy>(ListParams::default());
tokio::spawn(
kubert::index::namespaced(index.clone(), authz_policies)
.instrument(info_span!("authorizationpolicies")),
);
let mtls_authns =
runtime.watch_all::<k8s::policy::MeshTLSAuthentication>(ListParams::default());
tokio::spawn(
kubert::index::namespaced(index.clone(), mtls_authns)
.instrument(info_span!("meshtlsauthentications")),
);
let network_authns =
runtime.watch_all::<k8s::policy::NetworkAuthentication>(ListParams::default());
tokio::spawn(
kubert::index::namespaced(index.clone(), network_authns)
.instrument(info_span!("networkauthentications")),
);
// Run the gRPC server, serving results by looking up against the index handle.
tokio::spawn(grpc(
grpc_addr,

View File

@ -155,7 +155,7 @@ impl Runner {
args: Some(
vec![
"wait",
"--timeout=60s",
"--timeout=120s",
"--for=delete",
"--namespace",
ns,
@ -219,13 +219,22 @@ impl Running {
&self.name,
|obj: Option<&k8s::Pod>| -> bool { obj.and_then(get_exit_code).is_some() },
);
match time::timeout(time::Duration::from_secs(60), finished).await {
match time::timeout(time::Duration::from_secs(120), finished).await {
Ok(Ok(())) => {}
Ok(Err(error)) => panic!("Failed to wait for exit code: {}: {}", self.name, error),
Err(_timeout) => panic!("Timeout waiting for exit code: {}", self.name),
};
let curl_pod = api.get(&self.name).await.expect("pod must exist");
get_exit_code(&curl_pod).expect("curl pod must have an exit code")
let ex = get_exit_code(&curl_pod).expect("curl pod must have an exit code");
if let Err(error) = api
.delete(&self.name, &kube::api::DeleteParams::background())
.await
{
tracing::trace!(%error, name = %self.name, "Failed to delete pod");
}
ex
}
}

View File

@ -14,10 +14,10 @@ macro_rules! assert_is_default_all_unauthenticated {
($config:expr) => {
assert_eq!(
$config.labels,
Some((
"name".to_string(),
"default:all-unauthenticated".to_string()
))
vec![
("kind".to_string(), "default".to_string()),
("name".to_string(), "all-unauthenticated".to_string()),
]
.into_iter()
.collect()
);

View File

@ -0,0 +1,212 @@
use linkerd_policy_controller_k8s_api::{
self as api,
policy::{AuthorizationPolicy, AuthorizationPolicySpec, LocalTargetRef, NamespacedTargetRef},
};
use linkerd_policy_test::admission;
#[tokio::test(flavor = "current_thread")]
async fn accepts_valid() {
admission::accepts(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "api".to_string(),
},
required_authentication_refs: vec![
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "MeshTLSAuthentication".to_string(),
name: "mtls-clients".to_string(),
..Default::default()
},
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "NetworkAuthentication".to_string(),
name: "cluster-nets".to_string(),
namespace: Some("linkerd".to_string()),
},
],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn accepts_valid_with_only_meshtls() {
admission::accepts(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "api".to_string(),
},
required_authentication_refs: vec![NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "MeshTLSAuthentication".to_string(),
name: "mtls-clients".to_string(),
..Default::default()
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn accepts_valid_with_only_network() {
admission::accepts(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "api".to_string(),
},
required_authentication_refs: vec![NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "NetworkAuthentication".to_string(),
name: "cluster-nets".to_string(),
namespace: Some("linkerd".to_string()),
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_empty() {
admission::rejects(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec::default(),
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_empty_required_authentications() {
admission::rejects(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "deny".to_string(),
},
required_authentication_refs: vec![],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_target_ref_deployment() {
admission::rejects(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("apps".to_string()),
kind: "Deployment".to_string(),
name: "someapp".to_string(),
},
required_authentication_refs: vec![NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "NetworkAuthentication".to_string(),
namespace: Some("linkerd".to_string()),
name: "cluster-nets".to_string(),
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_duplicate_mtls_authns() {
admission::rejects(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "some-srv".to_string(),
},
required_authentication_refs: vec![
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "MeshTLSAuthentication".to_string(),
namespace: Some("some-ns".to_string()),
name: "some-ids".to_string(),
},
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "MeshTLSAuthentication".to_string(),
namespace: Some("other-ns".to_string()),
name: "other-ids".to_string(),
},
],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_duplicate_network_authns() {
admission::rejects(|ns| AuthorizationPolicy {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: AuthorizationPolicySpec {
target_ref: LocalTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "Server".to_string(),
name: "some-srv".to_string(),
},
required_authentication_refs: vec![
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "NetworkAuthentication".to_string(),
namespace: Some("some-ns".to_string()),
name: "some-nets".to_string(),
},
NamespacedTargetRef {
group: Some("policy.linkerd.io".to_string()),
kind: "NetworkAuthentication".to_string(),
namespace: Some("other-ns".to_string()),
name: "other-nets".to_string(),
},
],
},
})
.await;
}

View File

@ -0,0 +1,74 @@
use linkerd_policy_controller_k8s_api::{
self as api,
policy::{MeshTLSAuthentication, MeshTLSAuthenticationSpec, NamespacedTargetRef},
};
use linkerd_policy_test::admission;
#[tokio::test(flavor = "current_thread")]
async fn accepts_valid_ref() {
admission::accepts(|ns| MeshTLSAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: MeshTLSAuthenticationSpec {
identity_refs: Some(vec![NamespacedTargetRef {
kind: "ServiceAccount".to_string(),
name: "default".to_string(),
..Default::default()
}]),
..Default::default()
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn accepts_strings() {
admission::accepts(|ns| MeshTLSAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: MeshTLSAuthenticationSpec {
identities: Some(vec!["example.id".to_string()]),
..Default::default()
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_empty() {
admission::rejects(|ns| MeshTLSAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: MeshTLSAuthenticationSpec::default(),
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_both_refs_and_strings() {
admission::rejects(|ns| MeshTLSAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: MeshTLSAuthenticationSpec {
identities: Some(vec!["example.id".to_string()]),
identity_refs: Some(vec![NamespacedTargetRef {
kind: "ServiceAccount".to_string(),
name: "default".to_string(),
..Default::default()
}]),
},
})
.await;
}

View File

@ -0,0 +1,142 @@
use linkerd_policy_controller_k8s_api::{
self as api,
policy::network_authentication::{Network, NetworkAuthentication, NetworkAuthenticationSpec},
};
use linkerd_policy_test::admission;
#[tokio::test(flavor = "current_thread")]
async fn accepts_valid() {
admission::accepts(|ns| NetworkAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: NetworkAuthenticationSpec {
networks: vec![
Network {
cidr: "10.1.0.0/24".parse().unwrap(),
except: None,
},
Network {
cidr: "10.1.1.0/24".parse().unwrap(),
except: Some(vec!["10.1.1.0/28".parse().unwrap()]),
},
],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn accepts_ip_except() {
admission::accepts(|ns| NetworkAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: NetworkAuthenticationSpec {
networks: vec![Network {
cidr: "10.1.0.0/16".parse().unwrap(),
except: Some(vec!["10.1.1.1".parse().unwrap()]),
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_except_whole_cidr() {
admission::rejects(|ns| NetworkAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: NetworkAuthenticationSpec {
networks: vec![Network {
cidr: "10.1.1.0/24".parse().unwrap(),
except: Some(vec!["10.1.0.0/16".parse().unwrap()]),
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_except_not_in_cidr() {
admission::rejects(|ns| NetworkAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: NetworkAuthenticationSpec {
networks: vec![Network {
cidr: "10.1.1.0/24".parse().unwrap(),
except: Some(vec!["10.1.2.0/24".parse().unwrap()]),
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_invalid_cidr() {
// Duplicate the CRD with relaxed validation so we can send an invalid CIDR value.
#[derive(
Clone,
Debug,
Default,
kube::CustomResource,
serde::Deserialize,
serde::Serialize,
schemars::JsonSchema,
)]
#[kube(
group = "policy.linkerd.io",
version = "v1alpha1",
kind = "NetworkAuthentication",
namespaced
)]
#[serde(rename_all = "camelCase")]
pub struct NetworkAuthenticationSpec {
pub networks: Vec<Network>,
}
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct Network {
pub cidr: String,
pub except: Option<Vec<String>>,
}
admission::rejects(|ns| NetworkAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: NetworkAuthenticationSpec {
networks: vec![Network {
cidr: "10.1.0.0/16".to_string(),
except: Some(vec!["bogus".to_string()]),
}],
},
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn rejects_empty() {
admission::rejects(|ns| NetworkAuthentication {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: NetworkAuthenticationSpec { networks: vec![] },
})
.await;
}

View File

@ -1,5 +1,6 @@
use futures::prelude::*;
use kube::ResourceExt;
use linkerd_policy_controller_core::{Ipv4Net, Ipv6Net};
use linkerd_policy_controller_k8s_api as k8s;
use linkerd_policy_test::{
assert_is_default_all_unauthenticated, assert_protocol_detect, create, create_ready_pod, grpc,
@ -55,7 +56,7 @@ async fn server_with_server_authorization() {
assert_eq!(config.authorizations, vec![]);
assert_eq!(
config.labels,
convert_args!(hashmap!("name" => "linkerd-admin")),
convert_args!(hashmap!("kind" => "server", "name" => "linkerd-admin")),
);
// Create a server authorizaation that refers to the `linkerd-admin`
@ -99,6 +100,7 @@ async fn server_with_server_authorization() {
assert_eq!(
config.authorizations.first().unwrap().labels,
convert_args!(hashmap!(
"kind" => "serverauthorization",
"name" => "all-admin",
)),
);
@ -118,7 +120,7 @@ async fn server_with_server_authorization() {
);
assert_eq!(
config.labels,
convert_args!(hashmap!("name" => server.name()))
convert_args!(hashmap!("kind" => "server", "name" => server.name()))
);
// Delete the `Server` and ensure that the update reverts to the
@ -139,6 +141,142 @@ async fn server_with_server_authorization() {
.await;
}
/// Creates a pod, watches its policy, and updates policy resources that impact
/// the watch.
#[tokio::test(flavor = "current_thread")]
async fn server_with_authorization_policy() {
with_temp_ns(|client, ns| async move {
// Create a pod that does nothing. It's injected with a proxy, so we can
// attach policies to its admin server.
let pod = create_ready_pod(&client, mk_pause(&ns, "pause")).await;
tracing::trace!(?pod);
// Port-forward to the control plane and start watching the pod's admin
// server's policy and ensure that the first update uses the default
// policy.
let mut policy_api = grpc::PolicyClient::port_forwarded(&client).await;
let mut rx = policy_api
.watch_port(&ns, &pod.name(), 4191)
.await
.expect("failed to establish watch");
let config = rx
.next()
.await
.expect("watch must not fail")
.expect("watch must return an initial config");
tracing::trace!(?config);
assert_is_default_all_unauthenticated!(config);
assert_protocol_detect!(config);
// Create a server that selects the pod's proxy admin server and ensure
// that the update now uses this server, which has no authorizations
let server = create(&client, mk_admin_server(&ns, "linkerd-admin")).await;
let config = rx
.next()
.await
.expect("watch must not fail")
.expect("watch must return an updated config");
tracing::trace!(?config);
assert_eq!(
config.protocol,
Some(grpc::inbound::ProxyProtocol {
kind: Some(grpc::inbound::proxy_protocol::Kind::Http1(
grpc::inbound::proxy_protocol::Http1::default()
)),
}),
);
assert_eq!(config.authorizations, vec![]);
assert_eq!(
config.labels,
convert_args!(hashmap!("kind" => "server", "name" => server.name()))
);
let all_nets = create(
&client,
k8s::policy::NetworkAuthentication {
metadata: kube::api::ObjectMeta {
namespace: Some(ns.clone()),
name: Some("all-admin".to_string()),
..Default::default()
},
spec: k8s::policy::NetworkAuthenticationSpec {
networks: vec![
k8s::policy::network_authentication::Network {
cidr: Ipv4Net::default().into(),
except: None,
},
k8s::policy::network_authentication::Network {
cidr: Ipv6Net::default().into(),
except: None,
},
],
},
},
)
.await;
let authz_policy = create(
&client,
k8s::policy::AuthorizationPolicy {
metadata: kube::api::ObjectMeta {
namespace: Some(ns.clone()),
name: Some("all-admin".to_string()),
..Default::default()
},
spec: k8s::policy::AuthorizationPolicySpec {
target_ref: k8s::policy::LocalTargetRef::from_resource(&server),
required_authentication_refs: vec![
k8s::policy::NamespacedTargetRef::from_resource(&all_nets),
],
},
},
)
.await;
let config = time::timeout(time::Duration::from_secs(10), rx.next())
.await
.expect("watch must update within 10s")
.expect("watch must not fail")
.expect("watch must return an updated config");
tracing::trace!(?config);
assert_eq!(
config.protocol,
Some(grpc::inbound::ProxyProtocol {
kind: Some(grpc::inbound::proxy_protocol::Kind::Http1(
grpc::inbound::proxy_protocol::Http1::default()
)),
}),
);
assert_eq!(config.authorizations.len(), 1);
assert_eq!(
config.authorizations.first().unwrap().labels,
convert_args!(hashmap!(
"kind" => "authorizationpolicy",
"name" => authz_policy.name(),
))
);
assert_eq!(
*config
.authorizations
.first()
.unwrap()
.authentication
.as_ref()
.unwrap(),
grpc::inbound::Authn {
permit: Some(grpc::inbound::authn::Permit::Unauthenticated(
grpc::inbound::authn::PermitUnauthenticated {}
)),
}
);
assert_eq!(
config.labels,
convert_args!(hashmap!("kind" => "server", "name" => server.name()))
);
})
.await;
}
fn mk_pause(ns: &str, name: &str) -> k8s::Pod {
k8s::Pod {
metadata: k8s::ObjectMeta {

View File

@ -0,0 +1,375 @@
use linkerd_policy_controller_k8s_api::{
self as k8s,
policy::{LocalTargetRef, NamespacedTargetRef},
};
use linkerd_policy_test::{create, create_ready_pod, curl, nginx, with_temp_ns, LinkerdInject};
#[tokio::test(flavor = "current_thread")]
async fn meshtls() {
with_temp_ns(|client, ns| async move {
// First create all of the policies we'll need so that the nginx pod
// starts up with the correct policy (to prevent races).
//
// The policy requires that all connections are authenticated with MeshTLS.
let (srv, all_mtls) = tokio::join!(
create(&client, nginx::server(&ns)),
create(&client, all_authenticated(&ns))
);
create(
&client,
authz_policy(
&ns,
"nginx",
&srv,
Some(NamespacedTargetRef::from_resource(&all_mtls)),
),
)
.await;
// Create the nginx pod and wait for it to be ready.
tokio::join!(
create(&client, nginx::service(&ns)),
create_ready_pod(&client, nginx::pod(&ns))
);
let curl = curl::Runner::init(&client, &ns).await;
let (injected, uninjected) = tokio::join!(
curl.run("curl-injected", "http://nginx", LinkerdInject::Enabled),
curl.run("curl-uninjected", "http://nginx", LinkerdInject::Disabled),
);
let (injected_status, uninjected_status) =
tokio::join!(injected.exit_code(), uninjected.exit_code());
assert_eq!(
injected_status, 0,
"uninjected curl must fail to contact nginx"
);
assert_ne!(uninjected_status, 0, "injected curl must contact nginx");
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn network() {
// In order to test the network policy, we need to create the client pod
// before creating the authorization policy. To avoid races, we do this by
// creating a `curl-lock` configmap that prevents curl from actually being
// executed. Once nginx is running with the correct policy, the configmap is
// deleted to unblock the curl pods.
with_temp_ns(|client, ns| async move {
let curl = curl::Runner::init(&client, &ns).await;
curl.create_lock().await;
// Create a curl pod and wait for it to get an IP.
let blessed = curl
.run("curl-blessed", "http://nginx", LinkerdInject::Disabled)
.await;
let blessed_ip = blessed.ip().await;
tracing::debug!(curl.blessed.ip = %blessed_ip);
// Once we know the IP of the (blocked) pod, create an nginx
// authorization policy that permits connections from this pod.
let (srv, allow_ips) = tokio::join!(
create(&client, nginx::server(&ns)),
create(&client, allow_ips(&ns, Some(blessed_ip)))
);
create(
&client,
authz_policy(
&ns,
"nginx",
&srv,
Some(NamespacedTargetRef::from_resource(&allow_ips)),
),
)
.await;
// Start nginx with the policy.
tokio::join!(
create(&client, nginx::service(&ns)),
create_ready_pod(&client, nginx::pod(&ns))
);
// Once the nginx pod is ready, delete the `curl-lock` configmap to
// unblock curl from running.
curl.delete_lock().await;
// The blessed pod should be able to connect to the nginx pod.
let status = blessed.exit_code().await;
assert_eq!(status, 0, "blessed curl pod must succeed");
// Create another curl pod that is not included in the authorization. It
// should fail to connect to the nginx pod.
let status = curl
.run("curl-cursed", "http://nginx", LinkerdInject::Disabled)
.await
.exit_code()
.await;
assert_ne!(status, 0, "cursed curl pod must fail");
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn both() {
// In order to test the network policy, we need to create the client pod
// before creating the authorization policy. To avoid races, we do this by
// creating a `curl-lock` configmap that prevents curl from actually being
// executed. Once nginx is running with the correct policy, the configmap is
// deleted to unblock the curl pods.
with_temp_ns(|client, ns| async move {
let curl = curl::Runner::init(&client, &ns).await;
curl.create_lock().await;
let (blessed_injected, blessed_uninjected) = tokio::join!(
curl.run(
"curl-blessed-injected",
"http://nginx",
LinkerdInject::Enabled,
),
curl.run(
"curl-blessed-uninjected",
"http://nginx",
LinkerdInject::Disabled,
)
);
let (blessed_injected_ip, blessed_uninjected_ip) =
tokio::join!(blessed_injected.ip(), blessed_uninjected.ip(),);
tracing::debug!(curl.blessed.injected.ip = ?blessed_injected_ip);
tracing::debug!(curl.blessed.uninjected.ip = ?blessed_uninjected_ip);
// Once we know the IP of the (blocked) pod, create an nginx
// authorization policy that permits connections from this pod.
let (srv, allow_ips, all_mtls) = tokio::join!(
create(&client, nginx::server(&ns)),
create(
&client,
allow_ips(&ns, vec![blessed_injected_ip, blessed_uninjected_ip]),
),
create(&client, all_authenticated(&ns))
);
create(
&client,
authz_policy(
&ns,
"nginx",
&srv,
vec![
NamespacedTargetRef::from_resource(&allow_ips),
NamespacedTargetRef::from_resource(&all_mtls),
],
),
)
.await;
// Start nginx with the policy.
tokio::join!(
create(&client, nginx::service(&ns)),
create_ready_pod(&client, nginx::pod(&ns))
);
// Once the nginx pod is ready, delete the `curl-lock` configmap to
// unblock curl from running.
curl.delete_lock().await;
tracing::info!("unblocked curl");
let (blessed_injected_status, blessed_uninjected_status) =
tokio::join!(blessed_injected.exit_code(), blessed_uninjected.exit_code());
// The blessed and injected pod should be able to connect to the nginx pod.
assert_eq!(
blessed_injected_status, 0,
"blessed injected curl pod must succeed"
);
// The blessed and uninjected pod should NOT be able to connect to the nginx pod.
assert_ne!(
blessed_uninjected_status, 0,
"blessed uninjected curl pod must NOT succeed"
);
let (cursed_injected, cursed_uninjected) = tokio::join!(
curl.run(
"curl-cursed-injected",
"http://nginx",
LinkerdInject::Enabled,
),
curl.run(
"curl-cursed-uninjected",
"http://nginx",
LinkerdInject::Disabled,
)
);
let (cursed_injected_status, cursed_uninjected_status) =
tokio::join!(cursed_injected.exit_code(), cursed_uninjected.exit_code(),);
assert_ne!(
cursed_injected_status, 0,
"cursed injected curl pod must fail"
);
assert_ne!(
cursed_uninjected_status, 0,
"cursed uninjected curl pod must fail"
);
})
.await;
}
#[tokio::test(flavor = "current_thread")]
async fn either() {
// In order to test the network policy, we need to create the client pod
// before creating the authorization policy. To avoid races, we do this by
// creating a `curl-lock` configmap that prevents curl from actually being
// executed. Once nginx is running with the correct policy, the configmap is
// deleted to unblock the curl pods.
with_temp_ns(|client, ns| async move {
let curl = curl::Runner::init(&client, &ns).await;
curl.create_lock().await;
let (blessed_injected, blessed_uninjected) = tokio::join!(
curl.run(
"curl-blessed-injected",
"http://nginx",
LinkerdInject::Enabled,
),
curl.run(
"curl-blessed-uninjected",
"http://nginx",
LinkerdInject::Disabled,
)
);
let (blessed_injected_ip, blessed_uninjected_ip) =
tokio::join!(blessed_injected.ip(), blessed_uninjected.ip());
tracing::debug!(curl.blessed.injected.ip = ?blessed_injected_ip);
tracing::debug!(curl.blessed.uninjected.ip = ?blessed_uninjected_ip);
// Once we know the IP of the (blocked) pod, create an nginx
// authorization policy that permits connections from this pod.
let (srv, allow_ips, all_mtls) = tokio::join!(
create(&client, nginx::server(&ns)),
create(&client, allow_ips(&ns, vec![blessed_uninjected_ip])),
create(&client, all_authenticated(&ns))
);
tokio::join!(
create(
&client,
authz_policy(
&ns,
"nginx-from-ip",
&srv,
vec![NamespacedTargetRef::from_resource(&allow_ips)],
),
),
create(
&client,
authz_policy(
&ns,
"nginx-from-id",
&srv,
vec![NamespacedTargetRef::from_resource(&all_mtls)],
),
)
);
// Start nginx with the policy.
tokio::join!(
create(&client, nginx::service(&ns)),
create_ready_pod(&client, nginx::pod(&ns)),
);
// Once the nginx pod is ready, delete the `curl-lock` configmap to
// unblock curl from running.
curl.delete_lock().await;
tracing::info!("unblocking curl");
let (blessed_injected_status, blessed_uninjected_status) =
tokio::join!(blessed_injected.exit_code(), blessed_uninjected.exit_code());
// The blessed and injected pod should be able to connect to the nginx pod.
assert_eq!(
blessed_injected_status, 0,
"blessed injected curl pod must succeed"
);
// The blessed and uninjected pod should NOT be able to connect to the nginx pod.
assert_eq!(
blessed_uninjected_status, 0,
"blessed uninjected curl pod must succeed"
);
let (cursed_injected, cursed_uninjected) = tokio::join!(
curl.run(
"curl-cursed-injected",
"http://nginx",
LinkerdInject::Enabled,
),
curl.run(
"curl-cursed-uninjected",
"http://nginx",
LinkerdInject::Disabled,
),
);
let (cursed_injected_status, cursed_uninjected_status) =
tokio::join!(cursed_injected.exit_code(), cursed_uninjected.exit_code());
assert_eq!(
cursed_injected_status, 0,
"cursed injected curl pod must succeed"
);
assert_ne!(
cursed_uninjected_status, 0,
"cursed uninjected curl pod must fail"
);
})
.await;
}
// === helpers ===
fn authz_policy(
ns: &str,
name: &str,
target: &k8s::policy::Server,
authns: impl IntoIterator<Item = NamespacedTargetRef>,
) -> k8s::policy::AuthorizationPolicy {
k8s::policy::AuthorizationPolicy {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some(name.to_string()),
..Default::default()
},
spec: k8s::policy::AuthorizationPolicySpec {
target_ref: LocalTargetRef::from_resource(target),
required_authentication_refs: authns.into_iter().collect(),
},
}
}
fn all_authenticated(ns: &str) -> k8s::policy::MeshTLSAuthentication {
k8s::policy::MeshTLSAuthentication {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some("all-authenticated".to_string()),
..Default::default()
},
spec: k8s::policy::MeshTLSAuthenticationSpec {
identity_refs: None,
identities: Some(vec!["*".to_string()]),
},
}
}
fn allow_ips(
ns: &str,
ips: impl IntoIterator<Item = std::net::IpAddr>,
) -> k8s::policy::NetworkAuthentication {
k8s::policy::NetworkAuthentication {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
name: Some("allow-pod".to_string()),
..Default::default()
},
spec: k8s::policy::NetworkAuthenticationSpec {
networks: ips
.into_iter()
.map(|ip| k8s::policy::Network {
cidr: ip.into(),
except: None,
})
.collect(),
},
}
}