Skip to content

Commit c559147

Browse files
committed
[FeatureGate/KMSEncryptionProvider] APIServer config for AWS KMS
Signed-off-by: Swarup Ghosh <[email protected]>
1 parent fa836ae commit c559147

File tree

3 files changed

+218
-1
lines changed

3 files changed

+218
-1
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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 be able 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+
expected: |
45+
apiVersion: config.openshift.io/v1
46+
kind: APIServer
47+
spec:
48+
audit:
49+
profile: Default
50+
encryption:
51+
type: KMS
52+
kms:
53+
type: AWS
54+
aws:
55+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
56+
- name: Should not allow kms config with encrypt aescbc
57+
initial: |
58+
apiVersion: config.openshift.io/v1
59+
kind: APIServer
60+
spec:
61+
encryption:
62+
type: aescbc
63+
kms:
64+
type: AWS
65+
aws:
66+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
67+
expectedError: "kms config is required when encryption type is KMS, and forbidden otherwise"
68+
- name: Should fail to create with an empty KMS config
69+
initial: |
70+
apiVersion: config.openshift.io/v1
71+
kind: APIServer
72+
spec:
73+
encryption:
74+
type: KMS
75+
kms: {}
76+
expectedError: "spec.encryption.kms.type: Required value"
77+
- name: Should fail to create with kms type AWS but without aws config
78+
initial: |
79+
apiVersion: config.openshift.io/v1
80+
kind: APIServer
81+
spec:
82+
encryption:
83+
type: KMS
84+
kms:
85+
type: AWS
86+
expectedError: "aws config is required when kms provider type is AWS, and forbidden otherwise"
87+
- name: Should fail to create AWS KMS without a keyARN
88+
initial: |
89+
apiVersion: config.openshift.io/v1
90+
kind: APIServer
91+
spec:
92+
encryption:
93+
type: KMS
94+
kms:
95+
type: AWS
96+
aws:
97+
region: us-east-1
98+
expectedError: "spec.encryption.kms.aws.keyARN: Required value"
99+
- name: Should fail to create AWS KMS with invalid keyARN format
100+
initial: |
101+
apiVersion: config.openshift.io/v1
102+
kind: APIServer
103+
spec:
104+
encryption:
105+
type: KMS
106+
kms:
107+
type: AWS
108+
aws:
109+
keyARN: not-a-kms-arn
110+
region: us-east-1
111+
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 (-)."
112+
- name: Should fail to create AWS KMS with empty region
113+
initial: |
114+
apiVersion: config.openshift.io/v1
115+
kind: APIServer
116+
spec:
117+
encryption:
118+
type: KMS
119+
kms:
120+
type: AWS
121+
aws:
122+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
123+
region: ""
124+
expectedError: "spec.encryption.kms.aws.region in body should be at least 1 chars long"
125+
- name: Should fail to create AWS KMS with invalid region format
126+
initial: |
127+
apiVersion: config.openshift.io/v1
128+
kind: APIServer
129+
spec:
130+
encryption:
131+
type: KMS
132+
kms:
133+
type: AWS
134+
aws:
135+
keyARN: arn:aws:kms:us-east-1:101010101010:key/9a512e29-0d9c-4cf5-8174-fc1a5b22cd6a
136+
region: "INVALID-REGION"
137+
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+
// +optional
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)