Skip to content

Commit 06dfc05

Browse files
authored
Merge pull request #146 from pfnet/principal-integrity
Ensure principal and image pull secret integrity
2 parents 50e0eaa + 06f00ae commit 06dfc05

File tree

5 files changed

+520
-388
lines changed

5 files changed

+520
-388
lines changed

internal/controller/imagepullsecret.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ import (
2929
// buildImagePullSecret builds a Kubernetes Secret definition for an image pull secrets.
3030
// The built Secret will have
3131
// - a label to select them by the ServiceAccount name,
32-
// - an annotation to store the expiration time, and
32+
// - an annotation to store the principal and expiration time, and
3333
// - an owner reference to the ServiceAccount so that they will be deleted when the ServiceAccount no longer exists.
3434
func buildImagePullSecret(
3535
serviceAccount *corev1.ServiceAccount,
3636
secretName string,
3737
registry string,
3838
username string,
3939
password string,
40+
principal string,
4041
expiresAt time.Time,
4142
) (*corev1.Secret, error) {
4243
type dockerConfigEntry struct {
@@ -70,6 +71,7 @@ func buildImagePullSecret(
7071
labelKeyServiceAccount: serviceAccount.GetName(),
7172
},
7273
Annotations: map[string]string{
74+
annotationKeyPrincipal: principal,
7375
annotationKeyExpiresAt: expiresAt.Format(time.RFC3339),
7476
},
7577
OwnerReferences: []metav1.OwnerReference{

internal/controller/imagepullsecret_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ func TestBuildImagePullSecret(t *testing.T) {
4040
registry := "asia-northeast1-docker.pkg.dev"
4141
username := "oauth2accesstoken"
4242
password := "0xc0bebeef"
43+
principal := "[email protected]"
4344
expiresAt := time.Now().Add(time.Hour)
4445

45-
actual, err := buildImagePullSecret(sa, "secret-0", registry, username, password, expiresAt)
46+
actual, err := buildImagePullSecret(sa, "secret-0", registry, username, password, principal, expiresAt)
4647
if err != nil {
4748
t.Errorf("Failed to build an image pull secret: %v", err)
4849
}
@@ -54,6 +55,7 @@ func TestBuildImagePullSecret(t *testing.T) {
5455
"imagepullsecrets.preferred.jp/service-account": "serviceaccount-0",
5556
},
5657
Annotations: map[string]string{
58+
"imagepullsecrets.preferred.jp/principal": principal,
5759
"imagepullsecrets.preferred.jp/expires-at": expiresAt.Format(time.RFC3339),
5860
},
5961
OwnerReferences: []metav1.OwnerReference{

internal/controller/metadata.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const (
3333

3434
annotationKeySecretName = metadataKeyPrefix + "secret-name"
3535

36+
// Annotation for Secrets to store the principal used to provision the Secret.
37+
annotationKeyPrincipal = metadataKeyPrefix + "principal"
3638
// Annotation for Secrets to store the expiration time.
3739
annotationKeyExpiresAt = metadataKeyPrefix + "expires-at"
3840

internal/controller/serviceaccount_controller.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func (r *serviceAccountReconciler) provisionImagePullSecretForPrincipal(
157157
) (expiresAt time.Time, _ error) {
158158
logger := log.FromContext(ctx).WithValues("secret", secretName, "principal", principal)
159159

160-
should, exp, err := r.shouldCreateOrRefreshImagePullSecret(ctx, logger, sa, secretName)
160+
should, exp, err := r.shouldCreateOrRefreshImagePullSecret(ctx, logger, sa, secretName, principal)
161161
if err != nil {
162162
return time.Time{}, fmt.Errorf("failed to determine if an image pull secret should be created or refreshed: %w", err)
163163
}
@@ -183,10 +183,10 @@ func (r *serviceAccountReconciler) provisionImagePullSecretForPrincipal(
183183
}
184184

185185
func (r *serviceAccountReconciler) shouldCreateOrRefreshImagePullSecret(
186-
ctx context.Context, logger logr.Logger, sa *corev1.ServiceAccount, name string,
186+
ctx context.Context, logger logr.Logger, sa *corev1.ServiceAccount, secretName string, principal string,
187187
) (should bool, expiresAt time.Time, _ error) {
188188
// Check if the image pull secret exists.
189-
secretKey := client.ObjectKey{Namespace: sa.GetNamespace(), Name: name}
189+
secretKey := client.ObjectKey{Namespace: sa.GetNamespace(), Name: secretName}
190190

191191
secret := &corev1.Secret{}
192192
if err := r.Get(ctx, secretKey, secret); err != nil {
@@ -198,6 +198,14 @@ func (r *serviceAccountReconciler) shouldCreateOrRefreshImagePullSecret(
198198
return false, time.Time{}, fmt.Errorf("failed to check the existing of an image pull secret: %w", err)
199199
}
200200

201+
// Check if the image pull secret was provisioned for the principal.
202+
if secret.Annotations[annotationKeyPrincipal] != principal {
203+
logger.Info(
204+
"Image pull secret was provisioned for a different principal. Should be provisioned for the current one.",
205+
)
206+
return true, time.Time{}, nil
207+
}
208+
201209
// Check if the image pull secret is attached to the ServiceAccount.
202210
if !r.imagePullSecretAttached(sa, secret.GetName()) {
203211
logger.Info("Image pull secret is not attached to the ServiceAccount. Should be attached.")
@@ -248,7 +256,7 @@ func (r *serviceAccountReconciler) createOrRefreshImagePullSecret(
248256

249257
// Ensure an image pull secret from the access token.
250258
secret, err := buildImagePullSecret(
251-
sa, name, sa.Annotations[annotationKeyRegistry], username, token, expiresAt,
259+
sa, name, sa.Annotations[annotationKeyRegistry], username, token, principal, expiresAt,
252260
)
253261
if err != nil {
254262
return nil, time.Time{}, fmt.Errorf("failed to build image pull secret definition: %w", err)

0 commit comments

Comments
 (0)