Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ featureGates:
- KMSEncryptionProvider
tests:
onCreate:
- name: Should be able to create encrypt with KMS for AWS with valid values
- name: Should be able to create encrypt with KMS for External with valid endpoint
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
aws:
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
region: us-east-1
managementModel: External
endpoint: unix:///var/run/kmsplugin/socket.sock
expected: |
apiVersion: config.openshift.io/v1
kind: APIServer
Expand All @@ -26,22 +24,19 @@ tests:
encryption:
type: KMS
kms:
type: AWS
aws:
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
region: us-east-1
- name: Should fail to create encrypt with KMS for AWS without region
managementModel: External
endpoint: unix:///var/run/kmsplugin/socket.sock
- name: Should fail to create KMS with endpoint not starting with unix:///
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
aws:
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
expectedError: "spec.encryption.kms.aws.region: Required value"
managementModel: External
endpoint: /var/run/kmsplugin/socket.sock
expectedError: "endpoint must follow the format 'unix:///path'"
- name: Should not allow kms config with encrypt aescbc
initial: |
apiVersion: config.openshift.io/v1
Expand All @@ -50,10 +45,8 @@ tests:
encryption:
type: aescbc
kms:
type: AWS
aws:
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
region: us-east-1
managementModel: External
endpoint: unix:///var/run/kmsplugin/socket.sock
expectedError: "kms config is required when encryption type is KMS, and forbidden otherwise"
- name: Should fail to create with an empty KMS config
initial: |
Expand All @@ -63,65 +56,78 @@ tests:
encryption:
type: KMS
kms: {}
expectedError: "spec.encryption.kms.type: Required value"
- name: Should fail to create with kms type AWS but without aws config
expectedError: "spec.encryption.kms.endpoint: Required value"
- name: Should be able to create with default type when endpoint is provided
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
expectedError: "aws config is required when kms provider type is AWS, and forbidden otherwise"
- name: Should fail to create AWS KMS without a keyARN
endpoint: unix:///var/run/kmsplugin/socket.sock
expected: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
audit:
profile: Default
encryption:
type: KMS
kms:
managementModel: External
endpoint: unix:///var/run/kmsplugin/socket.sock
- name: Should fail to create KMS without endpoint
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
managementModel: External
expectedError: "spec.encryption.kms.endpoint: Required value"
- name: Should fail to create KMS with abstract socket endpoint
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
aws:
region: us-east-1
expectedError: "spec.encryption.kms.aws.keyARN: Required value"
- name: Should fail to create AWS KMS with invalid keyARN format
managementModel: External
endpoint: unix:///@abstractsocket
expectedError: "endpoint must follow the format 'unix:///path'"
- name: Should fail to create KMS with empty endpoint
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
aws:
keyARN: not-a-kms-arn
region: us-east-1
expectedError: "keyARN must follow the format `arn:aws:kms:<region>:<account_id>:key/<key_id>`. The account ID must be a 12 digit number and the region and key ID should consist only of lowercase hexadecimal characters and hyphens (-)."
- name: Should fail to create AWS KMS with empty region
managementModel: External
endpoint: ""
expectedError: "spec.encryption.kms.endpoint in body should be at least 9 chars long"
- name: Should fail to create KMS with endpoint containing spaces
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
aws:
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
region: ""
expectedError: "spec.encryption.kms.aws.region in body should be at least 1 chars long"
- name: Should fail to create AWS KMS with invalid region format
managementModel: External
endpoint: unix:///var/run/kms plugin/socket.sock
expectedError: "endpoint must follow the format 'unix:///path'"
- name: Should fail to create KMS with abstract socket containing slash
initial: |
apiVersion: config.openshift.io/v1
kind: APIServer
spec:
encryption:
type: KMS
kms:
type: AWS
aws:
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
region: "INVALID-REGION"
expectedError: "region must be a valid AWS region, consisting of lowercase characters, digits and hyphens (-) only."
managementModel: External
endpoint: unix:///@abstract/socket
expectedError: "endpoint must follow the format 'unix:///path'"
59 changes: 19 additions & 40 deletions config/v1/types_kmsencryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,33 @@ package v1

// KMSConfig defines the configuration for the KMS instance
// that will be used with KMSEncryptionProvider encryption
// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'AWS' ? has(self.aws) : !has(self.aws)",message="aws config is required when kms provider type is AWS, and forbidden otherwise"
// +union
type KMSConfig struct {
// type defines the kind of platform for the KMS provider.
// Available provider types are AWS only.
// managementModel defines how KMS plugins are managed.
// Valid values are "External".
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what would potentially be other possible values in the future? Would there be any cloud-provided specific plugins supported here since you mentioned that AWS is obsolete? Just trying to understand what would be the api changes would look like in the future.

// When set to External, encryption keys are managed by a user-deployed
// KMS plugin that communicates via UNIX domain socket using KMS V2 API.
//
// +unionDiscriminator
// +required
Type KMSProviderType `json:"type"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For serialization safety and to adhere to v1 API guarantees, we do not allow removal of any fields directly, even if it was only accessible in tech preview. Instead, we ask to tombstone them (removal with a comment), see some examples #2256 and #2576

This also means that the field name may not be used again, so we should be certain that we're ok with the removal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for review. That makes sense. I'll update this PR based on your comments, once we finalize the design.


// aws defines the key config for using an AWS KMS instance
// for the encryption. The AWS KMS instance is managed
// by the user outside the purview of the control plane.
//
// +unionMember
// +kubebuilder:validation:Enum=External
// +kubebuilder:default=External
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you help me understand why you'd like a default to be set here? We generally try not to set defaults via the API but instead through controllers and document the default behaviour via godocs, allowing for flexibility in the future. Since we only have one optional for now, is anything depending on this field to be explicitly set?

For additional context, see: https://github.com/openshift/enhancements/blob/master/dev-guide/api-conventions.md#defaulting

// +optional
AWS *AWSKMSConfig `json:"aws,omitempty"`
}
ManagementModel ManagementModel `json:"managementModel,omitempty"`

// AWSKMSConfig defines the KMS config specific to AWS KMS provider
type AWSKMSConfig struct {
// keyARN specifies the Amazon Resource Name (ARN) of the AWS KMS key used for encryption.
// The value must adhere to the format `arn:aws:kms:<region>:<account_id>:key/<key_id>`, where:
// - `<region>` is the AWS region consisting of lowercase letters and hyphens followed by a number.
// - `<account_id>` is a 12-digit numeric identifier for the AWS account.
// - `<key_id>` is a unique identifier for the KMS key, consisting of lowercase hexadecimal characters and hyphens.
//
// +kubebuilder:validation:MaxLength=128
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:XValidation:rule="self.matches('^arn:aws:kms:[a-z0-9-]+:[0-9]{12}:key/[a-f0-9-]+$')",message="keyARN must follow the format `arn:aws:kms:<region>:<account_id>:key/<key_id>`. The account ID must be a 12 digit number and the region and key ID should consist only of lowercase hexadecimal characters and hyphens (-)."
// +required
KeyARN string `json:"keyARN"`
// region specifies the AWS region where the KMS instance exists, and follows the format
// `<region-prefix>-<region-name>-<number>`, e.g.: `us-east-1`.
// Only lowercase letters and hyphens followed by numbers are allowed.
// endpoint specifies the UNIX domain socket endpoint for communicating with the external KMS plugin.
// The endpoint must follow the format "unix:///path".
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The endpoint must follow the format "unix:///path".
// The endpoint must follow the format "unix:///path" and be between 9 and 120 characters in length.

// Abstract Linux sockets (i.e. "unix:///@abstractname") are not supported.
//
// +kubebuilder:validation:MaxLength=64
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:XValidation:rule="self.matches('^[a-z0-9]+(-[a-z0-9]+)*$')",message="region must be a valid AWS region, consisting of lowercase characters, digits and hyphens (-) only."
// +kubebuilder:validation:MaxLength=120
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on https://man7.org/linux/man-pages/man7/unix.7.html ("Address format" section), maximum length is 108. It is less for mac. So I decided to set it to 120.

// +kubebuilder:validation:MinLength=9
// +kubebuilder:validation:XValidation:rule="self.matches('^unix:///[^@ ][^ ]*$')",message="endpoint must follow the format 'unix:///path'"
// +required
Region string `json:"region"`
Endpoint string `json:"endpoint,omitempty"`
}

// KMSProviderType is a specific supported KMS provider
// +kubebuilder:validation:Enum=AWS
type KMSProviderType string
// ManagementModel describes how the KMS plugin is managed.
// Valid values are "External".
type ManagementModel string

const (
// AWSKMSProvider represents a supported KMS provider for use with AWS KMS
AWSKMSProvider KMSProviderType = "AWS"
// External represents a KMS plugin that is managed externally and accessed via unix domain socket
External ManagementModel = "External"
)
Original file line number Diff line number Diff line change
Expand Up @@ -168,59 +168,30 @@ spec:
managing the lifecyle of the encryption keys outside of the control plane.
This allows integration with an external provider to manage the data encryption keys securely.
properties:
aws:
endpoint:
description: |-
aws defines the key config for using an AWS KMS instance
for the encryption. The AWS KMS instance is managed
by the user outside the purview of the control plane.
properties:
keyARN:
description: |-
keyARN specifies the Amazon Resource Name (ARN) of the AWS KMS key used for encryption.
The value must adhere to the format `arn:aws:kms:<region>:<account_id>:key/<key_id>`, where:
- `<region>` is the AWS region consisting of lowercase letters and hyphens followed by a number.
- `<account_id>` is a 12-digit numeric identifier for the AWS account.
- `<key_id>` is a unique identifier for the KMS key, consisting of lowercase hexadecimal characters and hyphens.
maxLength: 128
minLength: 1
type: string
x-kubernetes-validations:
- message: keyARN must follow the format `arn:aws:kms:<region>:<account_id>:key/<key_id>`.
The account ID must be a 12 digit number and the region
and key ID should consist only of lowercase hexadecimal
characters and hyphens (-).
rule: self.matches('^arn:aws:kms:[a-z0-9-]+:[0-9]{12}:key/[a-f0-9-]+$')
region:
description: |-
region specifies the AWS region where the KMS instance exists, and follows the format
`<region-prefix>-<region-name>-<number>`, e.g.: `us-east-1`.
Only lowercase letters and hyphens followed by numbers are allowed.
maxLength: 64
minLength: 1
type: string
x-kubernetes-validations:
- message: region must be a valid AWS region, consisting
of lowercase characters, digits and hyphens (-) only.
rule: self.matches('^[a-z0-9]+(-[a-z0-9]+)*$')
required:
- keyARN
- region
type: object
type:
endpoint specifies the UNIX domain socket endpoint for communicating with the external KMS plugin.
The endpoint must follow the format "unix:///path".
Abstract Linux sockets (i.e. "unix:///@abstractname") are not supported.
maxLength: 120
minLength: 9
type: string
x-kubernetes-validations:
- message: endpoint must follow the format 'unix:///path'
rule: self.matches('^unix:///[^@ ][^ ]*$')
managementModel:
default: External
description: |-
type defines the kind of platform for the KMS provider.
Available provider types are AWS only.
managementModel defines how KMS plugins are managed.
Valid values are "External".
When set to External, encryption keys are managed by a user-deployed
KMS plugin that communicates via UNIX domain socket using KMS V2 API.
enum:
- AWS
- External
type: string
required:
- type
- endpoint
type: object
x-kubernetes-validations:
- message: aws config is required when kms provider type is AWS,
and forbidden otherwise
rule: 'has(self.type) && self.type == ''AWS'' ? has(self.aws)
: !has(self.aws)'
type:
description: |-
type defines what encryption type should be used to encrypt resources at the datastore layer.
Expand Down
Loading