Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions api/v1/gitrepository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,23 @@ type GitRepositoryRef struct {
Commit string `json:"commit,omitempty"`
}

// CrossNamespaceObjectReference allows referencing a Secret or ConfigMap
// in another namespace.
type CrossNamespaceObjectReference struct {
// Name of the Secret or ConfigMap.
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`

// Namespace of the Secret or ConfigMap.
// +kubebuilder:validation:MinLength=1
Namespace string `json:"namespace"`

// Kind of the object being referenced: Secret or ConfigMap.
// +kubebuilder:validation:Enum=Secret;ConfigMap
Kind string `json:"kind"`
}


// GitRepositoryVerification specifies the Git commit signature verification
// strategy.
type GitRepositoryVerification struct {
Expand All @@ -235,6 +252,11 @@ type GitRepositoryVerification struct {
// authors.
// +required
SecretRef meta.LocalObjectReference `json:"secretRef"`

// PublicKeyRef allows referencing a Secret or ConfigMap in another namespace
// that contains the public key(s) for verification.
// +optional
PublicKeyRef *CrossNamespaceObjectReference `json:"publicKeyRef,omitempty"`
}

// GitRepositoryStatus records the observed state of a Git repository.
Expand Down
22 changes: 21 additions & 1 deletion api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,31 @@ spec:
- Tag
- TagAndHEAD
type: string
publicKeyRef:
description: |-
PublicKeyRef allows referencing a Secret or ConfigMap in another namespace
that contains the public key(s) for verification.
properties:
kind:
description: 'Kind of the object being referenced: Secret
or ConfigMap.'
enum:
- Secret
- ConfigMap
type: string
name:
description: Name of the Secret or ConfigMap.
minLength: 1
type: string
namespace:
description: Namespace of the Secret or ConfigMap.
minLength: 1
type: string
required:
- kind
- name
- namespace
type: object
secretRef:
description: |-
SecretRef specifies the Secret containing the public keys of trusted Git
Expand Down
15 changes: 8 additions & 7 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- ""
resources:
- configmaps
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- ""
resources:
Expand Down
78 changes: 60 additions & 18 deletions internal/controller/gitrepository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ func getPatchOptions(ownedConditions []string, controllerName string) []patch.Op
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/finalizers,verbs=get;create;update;patch;delete
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch

// GitRepositoryReconciler reconciles a v1.GitRepository object.
type GitRepositoryReconciler struct {
Expand Down Expand Up @@ -1073,25 +1074,66 @@ func (r *GitRepositoryReconciler) verifySignature(ctx context.Context, obj *sour
return sreconcile.ResultSuccess, nil
}

// Get secret with GPG data
publicKeySecret := types.NamespacedName{
Namespace: obj.Namespace,
Name: obj.Spec.Verification.SecretRef.Name,
}
secret := &corev1.Secret{}
if err := r.Client.Get(ctx, publicKeySecret, secret); err != nil {
e := serror.NewGeneric(
fmt.Errorf("PGP public keys secret error: %w", err),
"VerificationError",
)
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, "%s", e)
return sreconcile.ResultEmpty, e
}
var keyRings []string

if obj.Spec.Verification.PublicKeyRef != nil {
// new cross-namespace logic
ref := obj.Spec.Verification.PublicKeyRef
switch ref.Kind {
case "Secret":
var secret corev1.Secret
if err := r.Client.Get(ctx, types.NamespacedName{
Namespace: ref.Namespace,
Name: ref.Name,
}, &secret); err != nil {
e := serror.NewGeneric(
fmt.Errorf("PGP public keys secret error: %w", err),
"VerificationError",
)
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, "%s", e)
return sreconcile.ResultEmpty, e
}
for _, v := range secret.Data {
keyRings = append(keyRings, string(v))
}

case "ConfigMap":
var cm corev1.ConfigMap
if err := r.Client.Get(ctx, types.NamespacedName{
Namespace: ref.Namespace,
Name: ref.Name,
}, &cm); err != nil {
e := serror.NewGeneric(
fmt.Errorf("PGP public keys configmap error: %w", err),
"VerificationError",
)
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, "%s", e)
return sreconcile.ResultEmpty, e
}
for _, v := range cm.Data {
keyRings = append(keyRings, v)
}
}
} else {
// fallback to same-namespace SecretRef
publicKeySecret := types.NamespacedName{
Namespace: obj.Namespace,
Name: obj.Spec.Verification.SecretRef.Name,
}
secret := &corev1.Secret{}
if err := r.Client.Get(ctx, publicKeySecret, secret); err != nil {
e := serror.NewGeneric(
fmt.Errorf("PGP public keys secret error: %w", err),
"VerificationError",
)
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, "%s", e)
return sreconcile.ResultEmpty, e
}
for _, v := range secret.Data {
keyRings = append(keyRings, string(v))
}
}

var keyRings []string
for _, v := range secret.Data {
keyRings = append(keyRings, string(v))
}

var message strings.Builder
if obj.Spec.Verification.VerifyTag() {
Expand Down