1 package providerctl
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 "github.com/google/uuid"
9 "github.com/ory/x/randx"
10 apiv1 "k8s.io/api/core/v1"
11 "k8s.io/apimachinery/pkg/types"
12 ctrl "sigs.k8s.io/controller-runtime"
13 "sigs.k8s.io/controller-runtime/pkg/client"
14
15 apierrs "k8s.io/apimachinery/pkg/api/errors"
16
17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18 logger "sigs.k8s.io/controller-runtime/pkg/log"
19
20 api "edge-infra.dev/pkg/edge/iam/api/v1alpha1"
21 "edge-infra.dev/pkg/edge/iam/crypto"
22 )
23
24 const (
25 PrivateKeysSecretName = "private-key-secret"
26 ChallengeSecretName = "challenge-secret"
27 )
28
29 func (r *ProviderReconciler) reconcilePrivateKeysSecret(ctx context.Context, req ctrl.Request, provider api.Provider) (api.Provider, *apiv1.Secret, error) {
30 log := logger.FromContext(ctx)
31 secret, err := secretExists(ctx, req, r.Client, PrivateKeysSecretName)
32 if err != nil {
33 log.Info("failed to check if secret exists. will retry soon", "ns", req.Namespace, "secret", PrivateKeysSecretName)
34 return api.NotReady(provider, SecretExistCheckFailure, err.Error()), nil, err
35 }
36
37
38 if secret != nil {
39 return provider, secret, nil
40 }
41
42
43 secret, err = r.createPrivateKeysSecret(ctx, provider)
44 if err != nil {
45 log.Info("failed to check if secret exists. will retry soon", "ns", req.Namespace, "secret", PrivateKeysSecretName)
46 return api.NotReady(provider, SecretCreationFailure, err.Error()), nil, err
47 }
48
49 log.Info("successfully created secret", "ns", req.Namespace, "name", PrivateKeysSecretName)
50 return provider, secret, nil
51 }
52
53 func (r *ProviderReconciler) createPrivateKeysSecret(ctx context.Context, provider api.Provider) (*apiv1.Secret, error) {
54 secret := apiv1.Secret{}
55 secret.ObjectMeta = metav1.ObjectMeta{
56 Name: PrivateKeysSecretName,
57 Namespace: provider.Namespace,
58 }
59
60 pk := crypto.CreatePrivateKey()
61 serializedPrivateKey := crypto.Serialize(pk)
62 secret.Data = map[string][]byte{
63 "private_key": []byte(serializedPrivateKey),
64 "private_key_id": []byte(uuid.New().String()),
65 }
66
67 err := r.Create(ctx, &secret)
68 if err != nil {
69 return nil, fmt.Errorf("failed to create private keys secret name '%v'", PrivateKeysSecretName)
70 }
71
72 return &secret, nil
73 }
74
75 func (r *ProviderReconciler) validatePrivateKeysSecret(provider api.Provider, secret *apiv1.Secret) (api.Provider, error) {
76 _, found := secret.Data["private_key"]
77 if !found {
78 e := errors.New(`"private_key property missing"`)
79 return api.NotReady(provider, MissingSecretData, e.Error()), e
80 }
81
82 _, found = secret.Data["private_key_id"]
83 if !found {
84 e := errors.New(`"private_key_id property missing"`)
85 return api.NotReady(provider, MissingSecretData, e.Error()), e
86 }
87
88 return provider, nil
89 }
90
91 func (r *ProviderReconciler) validateChallengeSecret(provider api.Provider, secret *apiv1.Secret) (api.Provider, error) {
92 _, found := secret.Data["secret"]
93 if !found {
94 e := errors.New(`"secret property missing"`)
95 return api.NotReady(provider, MissingSecretData, e.Error()), e
96 }
97
98 return provider, nil
99 }
100
101 func secretExists(ctx context.Context, req ctrl.Request, c client.Client, secretName string) (*apiv1.Secret, error) {
102 secret := &apiv1.Secret{}
103 err := c.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: secretName}, secret)
104 switch {
105 case err == nil:
106 return secret, nil
107 case apierrs.IsNotFound(err):
108 return nil, nil
109 default:
110 return nil, fmt.Errorf("failed to check if secret exists: %w", err)
111 }
112 }
113
114 func (r *ProviderReconciler) reconcileChallengeSecret(ctx context.Context, req ctrl.Request, provider api.Provider) (api.Provider, *apiv1.Secret, error) {
115 log := logger.FromContext(ctx)
116
117 secret, err := secretExists(ctx, req, r.Client, ChallengeSecretName)
118 if err != nil {
119 log.Info("failed to check if secret exists. will retry soon", "ns", req.Namespace, "secret", ChallengeSecretName)
120 return api.NotReady(provider, SecretExistCheckFailure, err.Error()), nil, err
121 }
122
123
124 if secret != nil {
125 return provider, secret, nil
126 }
127
128
129 secret, err = r.createChallengeSecret(ctx, provider)
130 if err != nil {
131 log.Info("failed to create secret. will retry soon", "ns", req.Namespace, "secret", ChallengeSecretName)
132 return api.NotReady(provider, SecretCreationFailure, err.Error()), nil, err
133 }
134
135 log.Info("successfully created secret", "ns", req.Namespace, "name", ChallengeSecretName)
136 return provider, secret, nil
137 }
138
139 func (r *ProviderReconciler) createChallengeSecret(ctx context.Context, provider api.Provider) (*apiv1.Secret, error) {
140 secret := apiv1.Secret{}
141 secret.ObjectMeta = metav1.ObjectMeta{
142 Name: ChallengeSecretName,
143 Namespace: provider.Namespace,
144 }
145
146 s, _ := generateSecret(32)
147 secret.Data = map[string][]byte{
148 "secret": s,
149 }
150
151 err := r.Create(ctx, &secret)
152 if err != nil {
153 return nil, fmt.Errorf("failed to create challenge secret name '%v'", ChallengeSecretName)
154 }
155
156 return &secret, nil
157 }
158
159 var secretCharSet = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
160
161 func generateSecret(length int) ([]byte, error) {
162 secret, err := randx.RuneSequence(length, secretCharSet)
163 if err != nil {
164 return []byte{}, err
165 }
166 return []byte(string(secret)), nil
167 }
168
View as plain text