Provisioning: Encrypt webhook secret (#100612)

* feat: encrypt webhook secret

* chore: regen code
This commit is contained in:
Mariell Hoversholm
2025-02-13 16:27:55 +01:00
committed by GitHub
parent e83f764da9
commit 1f36907481
8 changed files with 43 additions and 1 deletions
+1
View File
@@ -207,6 +207,7 @@ type WebhookStatus struct {
ID int64 `json:"id,omitempty"`
URL string `json:"url,omitempty"`
Secret string `json:"secret,omitempty"`
EncryptedSecret []byte `json:"encryptedSecret,omitempty"`
SubscribedEvents []string `json:"subscribedEvents,omitempty"`
}
@@ -857,6 +857,11 @@ func (in *WebhookResponse) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WebhookStatus) DeepCopyInto(out *WebhookStatus) {
*out = *in
if in.EncryptedSecret != nil {
in, out := &in.EncryptedSecret, &out.EncryptedSecret
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.SubscribedEvents != nil {
in, out := &in.SubscribedEvents, &out.SubscribedEvents
*out = make([]string, len(*in))
@@ -1909,6 +1909,12 @@ func schema_pkg_apis_provisioning_v0alpha1_WebhookStatus(ref common.ReferenceCal
Format: "",
},
},
"encryptedSecret": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "byte",
},
},
"subscribedEvents": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
@@ -10,6 +10,7 @@ type WebhookStatusApplyConfiguration struct {
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Secret *string `json:"secret,omitempty"`
EncryptedSecret []byte `json:"encryptedSecret,omitempty"`
SubscribedEvents []string `json:"subscribedEvents,omitempty"`
}
@@ -43,6 +44,16 @@ func (b *WebhookStatusApplyConfiguration) WithSecret(value string) *WebhookStatu
return b
}
// WithEncryptedSecret adds the given value to the EncryptedSecret field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the EncryptedSecret field.
func (b *WebhookStatusApplyConfiguration) WithEncryptedSecret(values ...byte) *WebhookStatusApplyConfiguration {
for i := range values {
b.EncryptedSecret = append(b.EncryptedSecret, values[i])
}
return b
}
// WithSubscribedEvents adds the given value to the SubscribedEvents field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the SubscribedEvents field.
@@ -804,5 +804,14 @@ func (b *APIBuilder) encryptSecrets(ctx context.Context, repo *provisioning.Repo
}
repo.Spec.GitHub.Token = ""
}
if repo.Status.Webhook != nil &&
repo.Status.Webhook.Secret != "" {
repo.Status.Webhook.EncryptedSecret, err = b.secrets.Encrypt(ctx, []byte(repo.Status.Webhook.Secret))
if err != nil {
return err
}
repo.Status.Webhook.Secret = ""
}
return nil
}
@@ -525,7 +525,12 @@ func (r *githubRepository) Webhook(ctx context.Context, req *http.Request) (*pro
return nil, fmt.Errorf("unexpected webhook request")
}
payload, err := github.ValidatePayload(req, []byte(r.config.Status.Webhook.Secret))
secret, err := r.secrets.Decrypt(ctx, r.config.Status.Webhook.EncryptedSecret)
if err != nil {
return nil, fmt.Errorf("failed to decrypt secret: %w", err)
}
payload, err := github.ValidatePayload(req, secret)
if err != nil {
return nil, apierrors.NewUnauthorized("invalid signature")
}
@@ -4007,6 +4007,10 @@
"com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.WebhookStatus": {
"type": "object",
"properties": {
"encryptedSecret": {
"type": "string",
"format": "byte"
},
"id": {
"type": "integer",
"format": "int64"
@@ -829,6 +829,7 @@ export type SyncStatus = {
state: 'error' | 'pending' | 'success' | 'working';
};
export type WebhookStatus = {
encryptedSecret?: string;
id?: number;
secret?: string;
subscribedEvents?: string[];