From df79d110285f1956f63206e7bc1f29e49dd6f088 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Mon, 24 Jun 2024 10:43:11 +0200 Subject: [PATCH] implement flush for dedicated key, allow delete & key rotation --- garage.go | 11 +++++++++ website.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/garage.go b/garage.go index fabd6bf..44b8dae 100644 --- a/garage.go +++ b/garage.go @@ -55,6 +55,17 @@ func grgSearchKey(name string) (*garage.KeyInfo, error) { return resp, nil } +func grgDelKey(accessKey string) error { + client, ctx := gadmin() + + _, err := client.KeyApi.DeleteKey(ctx).Id(accessKey).Execute() + if err != nil { + fmt.Printf("%+v\n", err) + return err + } + return nil +} + func grgCreateBucket(bucket string) (*garage.BucketInfo, error) { client, ctx := gadmin() diff --git a/website.go b/website.go index e581780..d0bed9c 100644 --- a/website.go +++ b/website.go @@ -134,8 +134,14 @@ func (w *WebsiteController) getDedicatedWebsiteKey(binfo *garage.BucketInfo) (*g log.Printf("Created dedicated key %s\n", dedicatedKeyName) } + // Check that the key name is *exactly* the one we requested + if *keyInfo.Name != dedicatedKeyName { + log.Printf("Expected key: %s, got %s. Invariant violated.\n", dedicatedKeyName, *keyInfo.Name) + return nil, ErrDedicatedKeyInvariant + } + // Check that the dedicated key does not contain any other bucket than this one - // and that this bucket key is found with correct permissions + // and report if this bucket key is found with correct permissions permissionsOk := false for _, buck := range keyInfo.Buckets { if *buck.Id != *binfo.Id { @@ -167,7 +173,57 @@ func (w *WebsiteController) getDedicatedWebsiteKey(binfo *garage.BucketInfo) (*g return keyInfo, nil } -//@TODO: flushDedicatedWebsiteKey() +func (w *WebsiteController) flushDedicatedWebsiteKey(binfo *garage.BucketInfo) error { + // Check bucket info is not null + if binfo == nil { + return ErrFetchBucketInfo + } + + // Check the bucket is owned by the user's root key + usersRootKeyFound := false + for _, bucketKeyInfo := range binfo.Keys { + if *bucketKeyInfo.AccessKeyId == *w.RootKey.AccessKeyId && *bucketKeyInfo.Permissions.Owner { + usersRootKeyFound = true + break + } + } + if !usersRootKeyFound { + log.Printf("%s is not an owner of bucket %s. Invariant violated.\n", w.User.Username, *binfo.Id) + return ErrDedicatedKeyInvariant + } + + // Build the string template by concatening the username and the bucket identifier + dedicatedKeyName := fmt.Sprintf("%s:web:%s", w.User.Username, *binfo.Id) + + // Fetch the dedicated key + keyInfo, err := grgSearchKey(dedicatedKeyName) + if err != nil { + return err + } + + // Check that the key name is *exactly* the one we requested + if *keyInfo.Name != dedicatedKeyName { + log.Printf("Expected key: %s, got %s. Invariant violated.\n", dedicatedKeyName, *keyInfo.Name) + return ErrDedicatedKeyInvariant + } + + // Check that the dedicated key contains no other bucket than this one + // (can also be empty, useful to heal a partially created key) + for _, buck := range keyInfo.Buckets { + if *buck.Id != *binfo.Id { + log.Printf("Key %s is used on bucket %s while it should be exclusive to %s. Invariant violated.\n", dedicatedKeyName, *buck.Id, *binfo.Id) + return ErrDedicatedKeyInvariant + } + } + + // Finally delete this key + err = grgDelKey(*keyInfo.AccessKeyId) + if err != nil { + return err + } + log.Printf("Deleted dedicated key %s", dedicatedKeyName) + return nil +} func (w *WebsiteController) Describe() (*WebsiteDescribe, error) { r := make([]*WebsiteId, 0, len(w.PrettyList)) @@ -243,7 +299,10 @@ func (w *WebsiteController) Patch(pretty string, patch *WebsitePatch) (*WebsiteV } if patch.RotateKey != nil && *patch.RotateKey { - // @TODO: rotate key by calling flush + err = w.flushDedicatedWebsiteKey(binfo) + if err != nil { + return nil, err + } } dedicatedKey, err := w.getDedicatedWebsiteKey(binfo) @@ -327,7 +386,10 @@ func (w *WebsiteController) Delete(pretty string) error { } // Delete dedicated key - // @TODO call flush + err = w.flushDedicatedWebsiteKey(binfo) + if err != nil { + return err + } // Actually delete bucket err = grgDeleteBucket(website.Internal)