Skip to content

Commit 80acfbb

Browse files
authored
[Feature] Encryption Key rotation (#570)
1 parent 4d1b1e7 commit 80acfbb

37 files changed

+1641
-168
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Change Log
22

33
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
4+
- Add Encryption Key rotation feature for ArangoDB EE 3.7+
45

56
## [1.0.3](https://github.com/arangodb/kube-arangodb/tree/1.0.3) (2020-05-25)
67
- Prevent deletion of not known PVC's

pkg/apis/deployment/v1/deployment_spec.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ type DeploymentSpec struct {
6767

6868
RestoreFrom *string `json:"restoreFrom,omitempty"`
6969

70+
RestoreEncryptionSecret *string `json:"restoreEncryptionSecret,omitempty"`
71+
7072
// AllowUnsafeUpgrade determines if upgrade on missing member or with not in sync shards is allowed
7173
AllowUnsafeUpgrade *bool `json:"allowUnsafeUpgrade,omitempty"`
7274

pkg/apis/deployment/v1/plan.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ const (
7979
ActionTypeBackupRestore ActionType = "BackupRestore"
8080
// ActionTypeBackupRestoreClean restore plan
8181
ActionTypeBackupRestoreClean ActionType = "BackupRestoreClean"
82+
// ActionTypeEncryptionKeyAdd add new encryption key to list
83+
ActionTypeEncryptionKeyAdd ActionType = "EncryptionKeyAdd"
84+
// ActionTypeEncryptionKeyRemove removes encryption key to list
85+
ActionTypeEncryptionKeyRemove ActionType = "EncryptionKeyRemove"
86+
// ActionTypeEncryptionKeyRefresh refresh encryption keys
87+
ActionTypeEncryptionKeyRefresh ActionType = "EncryptionKeyRefresh"
8288
)
8389

8490
const (

pkg/apis/deployment/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/deployment/client/client.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2020 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Adam Janikowski
21+
//
22+
23+
package client
24+
25+
import (
26+
"context"
27+
"net/http"
28+
29+
"github.com/arangodb/go-driver"
30+
)
31+
32+
func NewClient(c driver.Connection) Client {
33+
return &client{
34+
c: c,
35+
}
36+
}
37+
38+
type Client interface {
39+
GetTLS(ctx context.Context) (TLSDetails, error)
40+
RefreshTLS(ctx context.Context) (TLSDetails, error)
41+
42+
GetEncryption(ctx context.Context) (EncryptionDetails, error)
43+
RefreshEncryption(ctx context.Context) (EncryptionDetails, error)
44+
}
45+
46+
type client struct {
47+
c driver.Connection
48+
}
49+
50+
func (c *client) parseTLSResponse(response driver.Response) (TLSDetails, error) {
51+
if err := response.CheckStatus(http.StatusOK); err != nil {
52+
return TLSDetails{}, err
53+
}
54+
55+
var d TLSDetails
56+
57+
if err := response.ParseBody("", &d); err != nil {
58+
return TLSDetails{}, err
59+
}
60+
61+
return d, nil
62+
}
63+
64+
func (c *client) parseEncryptionResponse(response driver.Response) (EncryptionDetails, error) {
65+
if err := response.CheckStatus(http.StatusOK); err != nil {
66+
return EncryptionDetails{}, err
67+
}
68+
69+
var d EncryptionDetails
70+
71+
if err := response.ParseBody("", &d); err != nil {
72+
return EncryptionDetails{}, err
73+
}
74+
75+
return d, nil
76+
}
77+
78+
func (c *client) GetTLS(ctx context.Context) (TLSDetails, error) {
79+
r, err := c.c.NewRequest(http.MethodGet, "/_admin/server/tls")
80+
if err != nil {
81+
return TLSDetails{}, err
82+
}
83+
84+
response, err := c.c.Do(ctx, r)
85+
if err != nil {
86+
return TLSDetails{}, err
87+
}
88+
89+
d, err := c.parseTLSResponse(response)
90+
if err != nil {
91+
return TLSDetails{}, err
92+
}
93+
94+
return d, nil
95+
}
96+
97+
func (c *client) RefreshTLS(ctx context.Context) (TLSDetails, error) {
98+
r, err := c.c.NewRequest(http.MethodPost, "/_admin/server/tls")
99+
if err != nil {
100+
return TLSDetails{}, err
101+
}
102+
103+
response, err := c.c.Do(ctx, r)
104+
if err != nil {
105+
return TLSDetails{}, err
106+
}
107+
108+
d, err := c.parseTLSResponse(response)
109+
if err != nil {
110+
return TLSDetails{}, err
111+
}
112+
113+
return d, nil
114+
}
115+
116+
func (c *client) GetEncryption(ctx context.Context) (EncryptionDetails, error) {
117+
r, err := c.c.NewRequest(http.MethodGet, "/_admin/server/encryption")
118+
if err != nil {
119+
return EncryptionDetails{}, err
120+
}
121+
122+
response, err := c.c.Do(ctx, r)
123+
if err != nil {
124+
return EncryptionDetails{}, err
125+
}
126+
127+
d, err := c.parseEncryptionResponse(response)
128+
if err != nil {
129+
return EncryptionDetails{}, err
130+
}
131+
132+
return d, nil
133+
}
134+
135+
func (c *client) RefreshEncryption(ctx context.Context) (EncryptionDetails, error) {
136+
r, err := c.c.NewRequest(http.MethodPost, "/_admin/server/encryption")
137+
if err != nil {
138+
return EncryptionDetails{}, err
139+
}
140+
141+
response, err := c.c.Do(ctx, r)
142+
if err != nil {
143+
return EncryptionDetails{}, err
144+
}
145+
146+
d, err := c.parseEncryptionResponse(response)
147+
if err != nil {
148+
return EncryptionDetails{}, err
149+
}
150+
151+
return d, nil
152+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2020 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Adam Janikowski
21+
//
22+
23+
package client
24+
25+
type EncryptionKeyEntry struct {
26+
Sha string `json:"sha256,omitempty"`
27+
}
28+
29+
type EncryptionDetailsResult struct {
30+
Keys []EncryptionKeyEntry `json:"encryption-keys,omitempty"`
31+
}
32+
33+
func (e EncryptionDetailsResult) KeysPresent(m map[string][]byte) bool {
34+
if len(e.Keys) != len(m) {
35+
return false
36+
}
37+
38+
for key := range m {
39+
ok := false
40+
for _, entry := range e.Keys {
41+
if entry.Sha == key {
42+
ok = true
43+
break
44+
}
45+
}
46+
if !ok {
47+
return false
48+
}
49+
}
50+
51+
return true
52+
}
53+
54+
type EncryptionDetails struct {
55+
Result EncryptionDetailsResult `json:"result,omitempty"`
56+
}

pkg/deployment/client/tls.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2020 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Adam Janikowski
21+
//
22+
23+
package client
24+
25+
type TLSKeyFile struct {
26+
PrivateKeyHash string `json:"privateKeySHA256,omitempty"`
27+
Checksum string `json:"SHA256,omitempty"`
28+
Certificates []string `json:"certificates,omitempty"`
29+
}
30+
31+
type TLSDetailsResult struct {
32+
KeyFile TLSKeyFile `json:"keyfile,omitempty"`
33+
SNI map[string]TLSKeyFile `json:"SNI,omitempty"`
34+
}
35+
36+
type TLSDetails struct {
37+
Result TLSDetailsResult `json:"result,omitempty"`
38+
}

pkg/deployment/context_impl.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,3 +504,7 @@ func (d *Deployment) WithStatusUpdate(action func(s *api.DeploymentStatus) bool,
504504
func (d *Deployment) SecretsInterface() k8sutil.SecretInterface {
505505
return d.GetKubeCli().CoreV1().Secrets(d.GetNamespace())
506506
}
507+
508+
func (d *Deployment) GetName() string {
509+
return d.apiObject.GetName()
510+
}

pkg/deployment/deployment.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ type deploymentEvent struct {
8383

8484
const (
8585
deploymentEventQueueSize = 256
86-
minInspectionInterval = util.Interval(time.Second) // Ensure we inspect the generated resources no less than with this interval
87-
maxInspectionInterval = util.Interval(time.Minute) // Ensure we inspect the generated resources no less than with this interval
86+
minInspectionInterval = 250 * util.Interval(time.Millisecond) // Ensure we inspect the generated resources no less than with this interval
87+
maxInspectionInterval = 30 * util.Interval(time.Second) // Ensure we inspect the generated resources no less than with this interval
8888
)
8989

9090
// Deployment is the in process state of an ArangoDeployment.

0 commit comments

Comments
 (0)