/
reconciler.go
100 lines (89 loc) · 3.82 KB
/
reconciler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package keypairs
import (
"context"
"fmt"
"github.com/awslabs/kubernetes-iteration-toolkit/operator/pkg/apis/controlplane/v1alpha1"
"github.com/awslabs/kubernetes-iteration-toolkit/operator/pkg/errors"
"github.com/awslabs/kubernetes-iteration-toolkit/operator/pkg/kubeprovider"
"github.com/awslabs/kubernetes-iteration-toolkit/operator/pkg/utils/object"
"github.com/awslabs/kubernetes-iteration-toolkit/operator/pkg/utils/secrets"
"go.uber.org/zap"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)
type Provider struct {
kubeClient *kubeprovider.Client
}
// CertTree contains root CA as the key and all the certificates signed by
// this root CA (leafs) are added as the value for this map
type CertTree map[*secrets.Request][]*secrets.Request
func Reconciler(kubeClient *kubeprovider.Client) *Provider {
return &Provider{kubeClient}
}
// ReconcileFor reconciles all certs/key requested as part of the certsTreeMap.
// All the cert/key pairs are stored as a secret object. It will first read the
// existing secret, if not found will create one.
func (c *Provider) ReconcileCertsFor(ctx context.Context, controlPlane *v1alpha1.ControlPlane, certsTreeMap CertTree) error {
for rootCA, leafCerts := range certsTreeMap {
// Get the existing CA from API server in the form of a Kube secret object,
// if not found or invalid generate a new one
caSecret, err := c.GetOrGenerateSecret(ctx, rootCA)
if err != nil {
return fmt.Errorf("creating root CA %v, %w", rootCA.Name, err)
}
secretObjs := []*v1.Secret{caSecret}
for _, leafCert := range leafCerts {
leafCert.CASecret = caSecret
// Get the existing cert and key from API server, if not found or
// invalid generate a new one
secretObj, err := c.GetOrGenerateSecret(ctx, leafCert)
if err != nil {
return fmt.Errorf("creating secret objects %v, %w", leafCert.Name, err)
}
secretObjs = append(secretObjs, secretObj)
}
for _, secret := range secretObjs {
if err = c.kubeClient.EnsureCreate(ctx, object.WithOwner(controlPlane, secret)); err != nil {
return fmt.Errorf("ensuring secret %v, %w", secret.Name, err)
}
}
}
zap.S().Debugf("[%v] Keypairs reconciled", controlPlane.ClusterName())
return nil
}
// GetOrGenerateSecret will check with API server for this object.
// Calls GetSecretFromServer to get from API server and validate
// If the object is not found, it will create and return a new secret object.
func (c *Provider) GetOrGenerateSecret(ctx context.Context, request *secrets.Request) (*v1.Secret, error) {
// get secret from api server
secret, err := c.GetSecretFromServer(ctx, object.NamespacedName(request.Name, request.Namespace))
if err != nil && errors.IsNotFound(err) {
// if not found generate a new secret object
return request.Create()
}
// validate the secret object contains valid secret data
if err := secrets.IsValid(secret); err != nil {
return nil, fmt.Errorf("invalid secret object %v/%v, %w", request.Namespace, request.Name, err)
}
return secret, err
}
// GetSecretFromServer will get the secret from API server and validate
func (c *Provider) GetSecretFromServer(ctx context.Context, nn types.NamespacedName) (*v1.Secret, error) {
// get secret from api server
secretObj := &v1.Secret{}
if err := c.kubeClient.Get(ctx, nn, secretObj); err != nil {
return nil, err
}
return secretObj, nil
}