Skip to content

Commit 62cf5e9

Browse files
Merge pull request #2035 from swghosh/kms-01
API-1843: FeatureGate(d) KMS encryption
2 parents 75d64d7 + 8ada9f6 commit 62cf5e9

18 files changed

+3998
-8
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this
2+
name: "APIServer"
3+
crdName: apiservers.config.openshift.io
4+
featureGates:
5+
- KMSEncryptionProvider
6+
tests:
7+
onCreate:
8+
- name: Should be able to create encrypt with KMS for AWS with valid values
9+
initial: |
10+
apiVersion: config.openshift.io/v1
11+
kind: APIServer
12+
spec:
13+
encryption:
14+
type: KMS
15+
kms:
16+
type: AWS
17+
aws:
18+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
19+
region: us-east-1
20+
expected: |
21+
apiVersion: config.openshift.io/v1
22+
kind: APIServer
23+
spec:
24+
audit:
25+
profile: Default
26+
encryption:
27+
type: KMS
28+
kms:
29+
type: AWS
30+
aws:
31+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
32+
region: us-east-1
33+
- name: Should fail to create encrypt with KMS for AWS without region
34+
initial: |
35+
apiVersion: config.openshift.io/v1
36+
kind: APIServer
37+
spec:
38+
encryption:
39+
type: KMS
40+
kms:
41+
type: AWS
42+
aws:
43+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
44+
expectedError: "spec.encryption.kms.aws.region: Required value"
45+
- name: Should not allow kms config with encrypt aescbc
46+
initial: |
47+
apiVersion: config.openshift.io/v1
48+
kind: APIServer
49+
spec:
50+
encryption:
51+
type: aescbc
52+
kms:
53+
type: AWS
54+
aws:
55+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
56+
region: us-east-1
57+
expectedError: "kms config is required when encryption type is KMS, and forbidden otherwise"
58+
- name: Should fail to create with an empty KMS config
59+
initial: |
60+
apiVersion: config.openshift.io/v1
61+
kind: APIServer
62+
spec:
63+
encryption:
64+
type: KMS
65+
kms: {}
66+
expectedError: "spec.encryption.kms.type: Required value"
67+
- name: Should fail to create with kms type AWS but without aws config
68+
initial: |
69+
apiVersion: config.openshift.io/v1
70+
kind: APIServer
71+
spec:
72+
encryption:
73+
type: KMS
74+
kms:
75+
type: AWS
76+
expectedError: "aws config is required when kms provider type is AWS, and forbidden otherwise"
77+
- name: Should fail to create AWS KMS without a keyARN
78+
initial: |
79+
apiVersion: config.openshift.io/v1
80+
kind: APIServer
81+
spec:
82+
encryption:
83+
type: KMS
84+
kms:
85+
type: AWS
86+
aws:
87+
region: us-east-1
88+
expectedError: "spec.encryption.kms.aws.keyARN: Required value"
89+
- name: Should fail to create AWS KMS with invalid keyARN format
90+
initial: |
91+
apiVersion: config.openshift.io/v1
92+
kind: APIServer
93+
spec:
94+
encryption:
95+
type: KMS
96+
kms:
97+
type: AWS
98+
aws:
99+
keyARN: not-a-kms-arn
100+
region: us-east-1
101+
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 (-)."
102+
- name: Should fail to create AWS KMS with empty region
103+
initial: |
104+
apiVersion: config.openshift.io/v1
105+
kind: APIServer
106+
spec:
107+
encryption:
108+
type: KMS
109+
kms:
110+
type: AWS
111+
aws:
112+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
113+
region: ""
114+
expectedError: "spec.encryption.kms.aws.region in body should be at least 1 chars long"
115+
- name: Should fail to create AWS KMS with invalid region format
116+
initial: |
117+
apiVersion: config.openshift.io/v1
118+
kind: APIServer
119+
spec:
120+
encryption:
121+
type: KMS
122+
kms:
123+
type: AWS
124+
aws:
125+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
126+
region: "INVALID-REGION"
127+
expectedError: "region must be a valid AWS region, consisting of lowercase characters, digits and hyphens (-) only."

config/v1/types_apiserver.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type APIServerSpec struct {
5151
// server from JavaScript applications.
5252
// The values are regular expressions that correspond to the Golang regular expression language.
5353
// +optional
54+
// +listType=atomic
5455
AdditionalCORSAllowedOrigins []string `json:"additionalCORSAllowedOrigins,omitempty"`
5556
// encryption allows the configuration of encryption of resources at the datastore layer.
5657
// +optional
@@ -153,6 +154,7 @@ type APIServerServingCerts struct {
153154
// If no named certificates are provided, or no named certificates match the server name as understood by a client,
154155
// the defaultServingCertificate will be used.
155156
// +optional
157+
// +listType=atomic
156158
NamedCertificates []APIServerNamedServingCert `json:"namedCertificates,omitempty"`
157159
}
158160

@@ -162,6 +164,7 @@ type APIServerNamedServingCert struct {
162164
// serve secure traffic. If no names are provided, the implicit names will be extracted from the certificates.
163165
// Exact names trump over wildcard names. Explicit names defined here trump over extracted implicit names.
164166
// +optional
167+
// +listType=atomic
165168
Names []string `json:"names,omitempty"`
166169
// servingCertificate references a kubernetes.io/tls type secret containing the TLS cert info for serving secure traffic.
167170
// The secret must exist in the openshift-config namespace and contain the following required fields:
@@ -170,6 +173,9 @@ type APIServerNamedServingCert struct {
170173
ServingCertificate SecretNameReference `json:"servingCertificate"`
171174
}
172175

176+
// APIServerEncryption is used to encrypt sensitive resources on the cluster.
177+
// +openshift:validation:FeatureGateAwareXValidation:featureGate=KMSEncryptionProvider,rule="has(self.type) && self.type == 'KMS' ? has(self.kms) : !has(self.kms)",message="kms config is required when encryption type is KMS, and forbidden otherwise"
178+
// +union
173179
type APIServerEncryption struct {
174180
// type defines what encryption type should be used to encrypt resources at the datastore layer.
175181
// When this field is unset (i.e. when it is set to the empty string), identity is implied.
@@ -188,9 +194,23 @@ type APIServerEncryption struct {
188194
// +unionDiscriminator
189195
// +optional
190196
Type EncryptionType `json:"type,omitempty"`
197+
198+
// kms defines the configuration for the external KMS instance that manages the encryption keys,
199+
// when KMS encryption is enabled sensitive resources will be encrypted using keys managed by an
200+
// externally configured KMS instance.
201+
//
202+
// The Key Management Service (KMS) instance provides symmetric encryption and is responsible for
203+
// managing the lifecyle of the encryption keys outside of the control plane.
204+
// This allows integration with an external provider to manage the data encryption keys securely.
205+
//
206+
// +openshift:enable:FeatureGate=KMSEncryptionProvider
207+
// +unionMember
208+
// +optional
209+
KMS *KMSConfig `json:"kms,omitempty"`
191210
}
192211

193-
// +kubebuilder:validation:Enum="";identity;aescbc;aesgcm
212+
// +openshift:validation:FeatureGateAwareEnum:featureGate="",enum="";identity;aescbc;aesgcm
213+
// +openshift:validation:FeatureGateAwareEnum:featureGate=KMSEncryptionProvider,enum="";identity;aescbc;aesgcm;KMS
194214
type EncryptionType string
195215

196216
const (
@@ -205,6 +225,11 @@ const (
205225
// aesgcm refers to a type where AES-GCM with random nonce and a 32-byte key
206226
// is used to perform encryption at the datastore layer.
207227
EncryptionTypeAESGCM EncryptionType = "aesgcm"
228+
229+
// kms refers to a type of encryption where the encryption keys are managed
230+
// outside the control plane in a Key Management Service instance,
231+
// encryption is still performed at the datastore layer.
232+
EncryptionTypeKMS EncryptionType = "KMS"
208233
)
209234

210235
type APIServerStatus struct {

config/v1/types_kmsencryption.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package v1
2+
3+
// KMSConfig defines the configuration for the KMS instance
4+
// that will be used with KMSEncryptionProvider encryption
5+
// +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"
6+
// +union
7+
type KMSConfig struct {
8+
// type defines the kind of platform for the KMS provider.
9+
// Available provider types are AWS only.
10+
//
11+
// +unionDiscriminator
12+
// +required
13+
Type KMSProviderType `json:"type"`
14+
15+
// aws defines the key config for using an AWS KMS instance
16+
// for the encryption. The AWS KMS instance is managed
17+
// by the user outside the purview of the control plane.
18+
//
19+
// +unionMember
20+
// +optional
21+
AWS *AWSKMSConfig `json:"aws,omitempty"`
22+
}
23+
24+
// AWSKMSConfig defines the KMS config specific to AWS KMS provider
25+
type AWSKMSConfig struct {
26+
// keyARN specifies the Amazon Resource Name (ARN) of the AWS KMS key used for encryption.
27+
// The value must adhere to the format `arn:aws:kms:<region>:<account_id>:key/<key_id>`, where:
28+
// - `<region>` is the AWS region consisting of lowercase letters and hyphens followed by a number.
29+
// - `<account_id>` is a 12-digit numeric identifier for the AWS account.
30+
// - `<key_id>` is a unique identifier for the KMS key, consisting of lowercase hexadecimal characters and hyphens.
31+
//
32+
// +kubebuilder:validation:MaxLength=128
33+
// +kubebuilder:validation:MinLength=1
34+
// +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 (-)."
35+
// +required
36+
KeyARN string `json:"keyARN"`
37+
// region specifies the AWS region where the KMS instance exists, and follows the format
38+
// `<region-prefix>-<region-name>-<number>`, e.g.: `us-east-1`.
39+
// Only lowercase letters and hyphens followed by numbers are allowed.
40+
//
41+
// +kubebuilder:validation:MaxLength=64
42+
// +kubebuilder:validation:MinLength=1
43+
// +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."
44+
// +required
45+
Region string `json:"region"`
46+
}
47+
48+
// KMSProviderType is a specific supported KMS provider
49+
// +kubebuilder:validation:Enum=AWS
50+
type KMSProviderType string
51+
52+
const (
53+
// AWSKMSProvider represents a supported KMS provider for use with AWS KMS
54+
AWSKMSProvider KMSProviderType = "AWS"
55+
)

0 commit comments

Comments
 (0)