Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CRDs for Permissive mTLS #2100

Merged
merged 3 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/2100.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
crd: Add `mutualTLSMode` to the ProxyDefaults and ServiceDefaults CRDs and `allowEnablingPermissiveMutualTLS` to the Mesh CRD to support configuring permissive mutual TLS.
```
5 changes: 5 additions & 0 deletions charts/consul/templates/crd-meshes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ spec:
spec:
description: MeshSpec defines the desired state of Mesh.
properties:
allowEnablingPermissiveMutualTLS:
description: AllowEnablingPermissiveMutualTLS must be true in order
to allow setting MutualTLSMode=permissive in either service-defaults
or proxy-defaults.
type: boolean
http:
description: HTTP defines the HTTP configuration for the service mesh.
properties:
Expand Down
12 changes: 12 additions & 0 deletions charts/consul/templates/crd-proxydefaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ spec:
CRD and should be set using annotations on the services that are
part of the mesh.'
type: string
mutualTLSMode:
description: 'MutualTLSMode controls whether mutual TLS is required
for all incoming connections when transparent proxy is enabled.
This can be set to "permissive" or "strict". "strict" is the default
which requires mutual TLS for incoming connections. In the insecure
"permissive" mode, connections to the sidecar proxy public listener
port require mutual TLS, but connections to the service port do
not require mutual TLS and are proxied to the application unmodified.
Note: Intentions are not enforced for non-mTLS connections. To keep
your services secure, we recommend using "strict" mode whenever
possible and enabling "permissive" mode only when necessary.'
type: string
transparentProxy:
description: 'TransparentProxy controls configuration specific to
proxies in transparent mode. Note: This cannot be set using the
Expand Down
12 changes: 12 additions & 0 deletions charts/consul/templates/crd-servicedefaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,18 @@ spec:
CRD and should be set using annotations on the services that are
part of the mesh.'
type: string
mutualTLSMode:
description: 'MutualTLSMode controls whether mutual TLS is required
for all incoming connections when transparent proxy is enabled.
This can be set to "permissive" or "strict". "strict" is the default
which requires mutual TLS for incoming connections. In the insecure
"permissive" mode, connections to the sidecar proxy public listener
port require mutual TLS, but connections to the service port do
not require mutual TLS and are proxied to the application unmodified.
Note: Intentions are not enforced for non-mTLS connections. To keep
your services secure, we recommend using "strict" mode whenever
possible and enabling "permissive" mode only when necessary.'
type: string
protocol:
description: Protocol sets the protocol of the service. This is used
by Connect proxies for things like observability features and to
Expand Down
14 changes: 9 additions & 5 deletions control-plane/api/v1alpha1/mesh_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type MeshList struct {
type MeshSpec struct {
// TransparentProxy controls the configuration specific to proxies in "transparent" mode. Added in v1.10.0.
TransparentProxy TransparentProxyMeshConfig `json:"transparentProxy,omitempty"`
// AllowEnablingPermissiveMutualTLS must be true in order to allow setting
// MutualTLSMode=permissive in either service-defaults or proxy-defaults.
AllowEnablingPermissiveMutualTLS bool `json:"allowEnablingPermissiveMutualTLS,omitempty"`
// TLS defines the TLS configuration for the service mesh.
TLS *MeshTLSConfig `json:"tls,omitempty"`
// HTTP defines the HTTP configuration for the service mesh.
Expand Down Expand Up @@ -192,11 +195,12 @@ func (in *Mesh) SetLastSyncedTime(time *metav1.Time) {

func (in *Mesh) ToConsul(datacenter string) capi.ConfigEntry {
return &capi.MeshConfigEntry{
TransparentProxy: in.Spec.TransparentProxy.toConsul(),
TLS: in.Spec.TLS.toConsul(),
HTTP: in.Spec.HTTP.toConsul(),
Peering: in.Spec.Peering.toConsul(),
Meta: meta(datacenter),
TransparentProxy: in.Spec.TransparentProxy.toConsul(),
AllowEnablingPermissiveMutualTLS: in.Spec.AllowEnablingPermissiveMutualTLS,
TLS: in.Spec.TLS.toConsul(),
HTTP: in.Spec.HTTP.toConsul(),
Peering: in.Spec.Peering.toConsul(),
Meta: meta(datacenter),
}
}

Expand Down
4 changes: 4 additions & 0 deletions control-plane/api/v1alpha1/mesh_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func TestMesh_MatchesConsul(t *testing.T) {
TransparentProxy: TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
AllowEnablingPermissiveMutualTLS: true,
TLS: &MeshTLSConfig{
Incoming: &MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_0",
Expand All @@ -72,6 +73,7 @@ func TestMesh_MatchesConsul(t *testing.T) {
TransparentProxy: capi.TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
AllowEnablingPermissiveMutualTLS: true,
TLS: &capi.MeshTLSConfig{
Incoming: &capi.MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_0",
Expand Down Expand Up @@ -148,6 +150,7 @@ func TestMesh_ToConsul(t *testing.T) {
TransparentProxy: TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
AllowEnablingPermissiveMutualTLS: true,
TLS: &MeshTLSConfig{
Incoming: &MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_0",
Expand All @@ -172,6 +175,7 @@ func TestMesh_ToConsul(t *testing.T) {
TransparentProxy: capi.TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
AllowEnablingPermissiveMutualTLS: true,
TLS: &capi.MeshTLSConfig{
Incoming: &capi.MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_0",
Expand Down
15 changes: 15 additions & 0 deletions control-plane/api/v1alpha1/proxydefaults_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ type ProxyDefaultsSpec struct {
// Note: This cannot be set using the CRD and should be set using annotations on the
// services that are part of the mesh.
TransparentProxy *TransparentProxy `json:"transparentProxy,omitempty"`
// MutualTLSMode controls whether mutual TLS is required for all incoming
// connections when transparent proxy is enabled. This can be set to
// "permissive" or "strict". "strict" is the default which requires mutual
// TLS for incoming connections. In the insecure "permissive" mode,
// connections to the sidecar proxy public listener port require mutual
// TLS, but connections to the service port do not require mutual TLS and
// are proxied to the application unmodified. Note: Intentions are not
// enforced for non-mTLS connections. To keep your services secure, we
// recommend using "strict" mode whenever possible and enabling
// "permissive" mode only when necessary.
MutualTLSMode MutualTLSMode `json:"mutualTLSMode,omitempty"`
// Config is an arbitrary map of configuration values used by Connect proxies.
// Any values that your proxy allows can be configured globally here.
// Supports JSON config values. See https://www.consul.io/docs/connect/proxies/envoy#configuration-formatting
Expand Down Expand Up @@ -174,6 +185,7 @@ func (in *ProxyDefaults) ToConsul(datacenter string) capi.ConfigEntry {
Expose: in.Spec.Expose.toConsul(),
Config: consulConfig,
TransparentProxy: in.Spec.TransparentProxy.toConsul(),
MutualTLSMode: in.Spec.MutualTLSMode.toConsul(),
AccessLogs: in.Spec.AccessLogs.toConsul(),
EnvoyExtensions: in.Spec.EnvoyExtensions.toConsul(),
FailoverPolicy: in.Spec.FailoverPolicy.toConsul(),
Expand Down Expand Up @@ -201,6 +213,9 @@ func (in *ProxyDefaults) Validate(_ common.ConsulMeta) error {
if err := in.Spec.TransparentProxy.validate(path.Child("transparentProxy")); err != nil {
allErrs = append(allErrs, err)
}
if err := in.Spec.MutualTLSMode.validate(); err != nil {
allErrs = append(allErrs, field.Invalid(path.Child("mutualTLSMode"), in.Spec.MutualTLSMode, err.Error()))
}
if err := in.Spec.Mode.validate(path.Child("mode")); err != nil {
allErrs = append(allErrs, err)
}
Expand Down
15 changes: 15 additions & 0 deletions control-plane/api/v1alpha1/proxydefaults_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func TestProxyDefaults_MatchesConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: MutualTLSModePermissive,
AccessLogs: &AccessLogs{
Enabled: true,
DisableListenerLogs: true,
Expand Down Expand Up @@ -129,6 +130,7 @@ func TestProxyDefaults_MatchesConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: capi.MutualTLSModePermissive,
AccessLogs: &capi.AccessLogsConfig{
Enabled: true,
DisableListenerLogs: true,
Expand Down Expand Up @@ -292,6 +294,7 @@ func TestProxyDefaults_ToConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: MutualTLSModeStrict,
AccessLogs: &AccessLogs{
Enabled: true,
DisableListenerLogs: true,
Expand Down Expand Up @@ -348,6 +351,7 @@ func TestProxyDefaults_ToConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: capi.MutualTLSModeStrict,
AccessLogs: &capi.AccessLogsConfig{
Enabled: true,
DisableListenerLogs: true,
Expand Down Expand Up @@ -497,6 +501,17 @@ func TestProxyDefaults_Validate(t *testing.T) {
},
expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode",
},
"mutualTLSMode": {
input: &ProxyDefaults{
ObjectMeta: metav1.ObjectMeta{
Name: "global",
},
Spec: ProxyDefaultsSpec{
MutualTLSMode: MutualTLSMode("asdf"),
},
},
expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.mutualTLSMode: Invalid value: "asdf": Must be one of "", "strict", or "permissive".`,
},
"accessLogs.type": {
input: &ProxyDefaults{
ObjectMeta: metav1.ObjectMeta{
Expand Down
15 changes: 15 additions & 0 deletions control-plane/api/v1alpha1/servicedefaults_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ type ServiceDefaultsSpec struct {
// Note: This cannot be set using the CRD and should be set using annotations on the
// services that are part of the mesh.
TransparentProxy *TransparentProxy `json:"transparentProxy,omitempty"`
// MutualTLSMode controls whether mutual TLS is required for all incoming
// connections when transparent proxy is enabled. This can be set to
// "permissive" or "strict". "strict" is the default which requires mutual
// TLS for incoming connections. In the insecure "permissive" mode,
// connections to the sidecar proxy public listener port require mutual
// TLS, but connections to the service port do not require mutual TLS and
// are proxied to the application unmodified. Note: Intentions are not
// enforced for non-mTLS connections. To keep your services secure, we
// recommend using "strict" mode whenever possible and enabling
// "permissive" mode only when necessary.
MutualTLSMode MutualTLSMode `json:"mutualTLSMode,omitempty"`
// MeshGateway controls the default mesh gateway configuration for this service.
MeshGateway MeshGateway `json:"meshGateway,omitempty"`
// Expose controls the default expose path configuration for Envoy.
Expand Down Expand Up @@ -279,6 +290,7 @@ func (in *ServiceDefaults) ToConsul(datacenter string) capi.ConfigEntry {
Expose: in.Spec.Expose.toConsul(),
ExternalSNI: in.Spec.ExternalSNI,
TransparentProxy: in.Spec.TransparentProxy.toConsul(),
MutualTLSMode: in.Spec.MutualTLSMode.toConsul(),
UpstreamConfig: in.Spec.UpstreamConfig.toConsul(),
Destination: in.Spec.Destination.toConsul(),
Meta: meta(datacenter),
Expand Down Expand Up @@ -306,6 +318,9 @@ func (in *ServiceDefaults) Validate(consulMeta common.ConsulMeta) error {
if err := in.Spec.TransparentProxy.validate(path.Child("transparentProxy")); err != nil {
allErrs = append(allErrs, err)
}
if err := in.Spec.MutualTLSMode.validate(); err != nil {
allErrs = append(allErrs, field.Invalid(path.Child("mutualTLSMode"), in.Spec.MutualTLSMode, err.Error()))
}
if err := in.Spec.Mode.validate(path.Child("mode")); err != nil {
allErrs = append(allErrs, err)
}
Expand Down
16 changes: 16 additions & 0 deletions control-plane/api/v1alpha1/servicedefaults_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: MutualTLSModePermissive,
UpstreamConfig: &Upstreams{
Defaults: &Upstream{
Name: "upstream-default",
Expand Down Expand Up @@ -197,6 +198,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: capi.MutualTLSModePermissive,
UpstreamConfig: &capi.UpstreamConfiguration{
Defaults: &capi.UpstreamConfig{
Name: "upstream-default",
Expand Down Expand Up @@ -367,6 +369,7 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: MutualTLSModeStrict,
UpstreamConfig: &Upstreams{
Defaults: &Upstream{
Name: "upstream-default",
Expand Down Expand Up @@ -487,6 +490,7 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) {
OutboundListenerPort: 1000,
DialedDirectly: true,
},
MutualTLSMode: capi.MutualTLSModeStrict,
UpstreamConfig: &capi.UpstreamConfiguration{
Defaults: &capi.UpstreamConfig{
Name: "upstream-default",
Expand Down Expand Up @@ -680,6 +684,7 @@ func TestServiceDefaults_Validate(t *testing.T) {
MeshGateway: MeshGateway{
Mode: "remote",
},
MutualTLSMode: MutualTLSModePermissive,
Expose: Expose{
Checks: false,
Paths: []ExposePath{
Expand Down Expand Up @@ -815,6 +820,17 @@ func TestServiceDefaults_Validate(t *testing.T) {
},
expectedErrMsg: "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port",
},
"mutualTLSMode": {
input: &ServiceDefaults{
ObjectMeta: metav1.ObjectMeta{
Name: "my-service",
},
Spec: ServiceDefaultsSpec{
MutualTLSMode: MutualTLSMode("asdf"),
},
},
expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.mutualTLSMode: Invalid value: "asdf": Must be one of "", "strict", or "permissive".`,
},
"mode": {
input: &ServiceDefaults{
ObjectMeta: metav1.ObjectMeta{
Expand Down
29 changes: 29 additions & 0 deletions control-plane/api/v1alpha1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,35 @@ type TransparentProxy struct {
DialedDirectly bool `json:"dialedDirectly,omitempty"`
}

type MutualTLSMode string

const (
// MutualTLSModeDefault represents no specific mode and should
// be used to indicate that a different layer of the configuration
// chain should take precedence.
MutualTLSModeDefault MutualTLSMode = ""

// MutualTLSModeStrict requires mTLS for incoming traffic.
MutualTLSModeStrict MutualTLSMode = "strict"

// MutualTLSModePermissive allows incoming non-mTLS traffic.
MutualTLSModePermissive MutualTLSMode = "permissive"
)

func (m MutualTLSMode) validate() error {
switch m {
case MutualTLSModeDefault, MutualTLSModeStrict, MutualTLSModePermissive:
return nil
}
return fmt.Errorf("Must be one of %q, %q, or %q.",
MutualTLSModeDefault, MutualTLSModeStrict, MutualTLSModePermissive,
)
}

func (m MutualTLSMode) toConsul() capi.MutualTLSMode {
return capi.MutualTLSMode(m)
}

// MeshGateway controls how Mesh Gateways are used for upstream Connect
// services.
type MeshGateway struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ spec:
spec:
description: MeshSpec defines the desired state of Mesh.
properties:
allowEnablingPermissiveMutualTLS:
description: AllowEnablingPermissiveMutualTLS must be true in order
to allow setting MutualTLSMode=permissive in either service-defaults
or proxy-defaults.
type: boolean
http:
description: HTTP defines the HTTP configuration for the service mesh.
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ spec:
CRD and should be set using annotations on the services that are
part of the mesh.'
type: string
mutualTLSMode:
description: 'MutualTLSMode controls whether mutual TLS is required
for all incoming connections when transparent proxy is enabled.
This can be set to "permissive" or "strict". "strict" is the default
which requires mutual TLS for incoming connections. In the insecure
"permissive" mode, connections to the sidecar proxy public listener
port require mutual TLS, but connections to the service port do
not require mutual TLS and are proxied to the application unmodified.
Note: Intentions are not enforced for non-mTLS connections. To keep
your services secure, we recommend using "strict" mode whenever
possible and enabling "permissive" mode only when necessary.'
type: string
transparentProxy:
description: 'TransparentProxy controls configuration specific to
proxies in transparent mode. Note: This cannot be set using the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ spec:
CRD and should be set using annotations on the services that are
part of the mesh.'
type: string
mutualTLSMode:
description: 'MutualTLSMode controls whether mutual TLS is required
for all incoming connections when transparent proxy is enabled.
This can be set to "permissive" or "strict". "strict" is the default
which requires mutual TLS for incoming connections. In the insecure
"permissive" mode, connections to the sidecar proxy public listener
port require mutual TLS, but connections to the service port do
not require mutual TLS and are proxied to the application unmodified.
Note: Intentions are not enforced for non-mTLS connections. To keep
your services secure, we recommend using "strict" mode whenever
possible and enabling "permissive" mode only when necessary.'
type: string
protocol:
description: Protocol sets the protocol of the service. This is used
by Connect proxies for things like observability features and to
Expand Down