github.com/nais/knorten@v0.0.0-20240104110906-55926958e361/pkg/gcp/iam.go (about) 1 package gcp 2 3 import ( 4 "context" 5 6 "cloud.google.com/go/iam" 7 secretmanager "cloud.google.com/go/secretmanager/apiv1" 8 "github.com/googleapis/gax-go/v2/apierror" 9 "google.golang.org/grpc/codes" 10 "k8s.io/utils/strings/slices" 11 ) 12 13 const secretRoleName = "roles/owner" 14 15 func SetUsersSecretOwnerBinding(ctx context.Context, users []string, secret string) error { 16 users = addUserTypePrefix(users) 17 18 client, err := secretmanager.NewClient(ctx) 19 if err != nil { 20 return err 21 } 22 defer client.Close() 23 24 handle := client.IAM(secret) 25 policy, err := handle.Policy(ctx) 26 if err != nil { 27 return err 28 } 29 30 policyMembers := policy.Members(secretRoleName) 31 for _, member := range policyMembers { 32 if !slices.Contains(users, member) { 33 policy.Remove(member, secretRoleName) 34 } 35 } 36 37 err = handle.SetPolicy(ctx, policy) 38 if err != nil { 39 return err 40 } 41 42 for _, user := range users { 43 if err := updatePolicy(ctx, handle, user); err != nil { 44 return err 45 } 46 } 47 48 return nil 49 } 50 51 func updatePolicy(ctx context.Context, handle *iam.Handle, user string) error { 52 policy, err := handle.Policy(ctx) 53 if err != nil { 54 return err 55 } 56 57 policyMembers := policy.Members(secretRoleName) 58 if !slices.Contains(policyMembers, user) { 59 policy.Add(user, secretRoleName) 60 err = handle.SetPolicy(ctx, policy) 61 if err != nil { 62 apiError, ok := apierror.FromError(err) 63 if ok && apiError.GRPCStatus().Code() == codes.InvalidArgument { 64 return nil 65 } 66 67 return err 68 } 69 } 70 71 return nil 72 } 73 74 func addUserTypePrefix(users []string) []string { 75 prefixedUsers := make([]string, len(users)) 76 for i, u := range users { 77 prefixedUsers[i] = "user:" + u 78 } 79 80 return prefixedUsers 81 }