Implement managed policy storage (#8385)

* Persist managed IAM policies

* Add IAM list/get policy integration test

* Faster marker lookup and cleanup

* Handle delete conflict and improve listing

* Add delete-in-use policy integration test

* Stabilize policy ID and guard path prefix

* Tighten CreatePolicy guard and reload

* Add ListPolicyNames to credential store
This commit is contained in:
Chris Lu
2026-02-19 14:21:19 -08:00
committed by GitHub
parent 5ecee9e64d
commit e9c45144cf
11 changed files with 464 additions and 14 deletions

View File

@@ -144,6 +144,11 @@ func (cm *CredentialManager) GetPolicy(ctx context.Context, name string) (*polic
return cm.Store.GetPolicy(ctx, name)
}
// ListPolicyNames returns the names of all policies
func (cm *CredentialManager) ListPolicyNames(ctx context.Context) ([]string, error) {
return cm.Store.ListPolicyNames(ctx)
}
// CreatePolicy creates a new policy (if supported by the store)
func (cm *CredentialManager) CreatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
// Check if the store implements PolicyManager interface with CreatePolicy

View File

@@ -71,6 +71,8 @@ type CredentialStore interface {
// Policy Management
GetPolicies(ctx context.Context) (map[string]policy_engine.PolicyDocument, error)
// ListPolicyNames returns the names of all policies
ListPolicyNames(ctx context.Context) ([]string, error)
// PutPolicy creates or replaces a policy document.
PutPolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error
DeletePolicy(ctx context.Context, name string) error

View File

@@ -235,3 +235,45 @@ func (store *FilerEtcStore) GetPolicy(ctx context.Context, name string) (*policy
return nil, nil // Policy not found
}
// ListPolicyNames returns all managed policy names stored in the filer.
func (store *FilerEtcStore) ListPolicyNames(ctx context.Context) ([]string, error) {
names := make([]string, 0)
store.mu.RLock()
configured := store.filerAddressFunc != nil
store.mu.RUnlock()
if !configured {
return names, nil
}
err := store.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
dir := filer.IamConfigDirectory + "/" + IamPoliciesDirectory
entries, err := listEntries(ctx, client, dir)
if err != nil {
if err == filer_pb.ErrNotFound {
return nil
}
return err
}
for _, entry := range entries {
if entry.IsDirectory {
continue
}
name := entry.Name
if strings.HasSuffix(name, ".json") {
name = name[:len(name)-5]
}
names = append(names, name)
}
return nil
})
if err != nil {
return nil, err
}
return names, nil
}

View File

@@ -79,6 +79,22 @@ func (store *IamGrpcStore) CreatePolicy(ctx context.Context, name string, docume
return store.PutPolicy(ctx, name, document)
}
// ListPolicyNames retrieves names of all IAM policies via gRPC.
func (store *IamGrpcStore) ListPolicyNames(ctx context.Context) ([]string, error) {
var names []string
err := store.withIamClient(func(client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.ListPolicies(ctx, &iam_pb.ListPoliciesRequest{})
if err != nil {
return err
}
for _, policy := range resp.Policies {
names = append(names, policy.Name)
}
return nil
})
return names, err
}
// UpdatePolicy updates an existing policy (delegates to PutPolicy)
func (store *IamGrpcStore) UpdatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
return store.PutPolicy(ctx, name, document)

View File

@@ -25,6 +25,23 @@ func (store *MemoryStore) GetPolicies(ctx context.Context) (map[string]policy_en
return policies, nil
}
// ListPolicyNames returns all stored policy names.
func (store *MemoryStore) ListPolicyNames(ctx context.Context) ([]string, error) {
store.mu.RLock()
defer store.mu.RUnlock()
if !store.initialized {
return nil, fmt.Errorf("store not initialized")
}
names := make([]string, 0, len(store.policies))
for name := range store.policies {
names = append(names, name)
}
return names, nil
}
// GetPolicy retrieves a specific IAM policy by name from memory
func (store *MemoryStore) GetPolicy(ctx context.Context, name string) (*policy_engine.PolicyDocument, error) {
store.mu.RLock()

View File

@@ -41,6 +41,30 @@ func (store *PostgresStore) GetPolicies(ctx context.Context) (map[string]policy_
return policies, nil
}
// ListPolicyNames returns all managed policy names from PostgreSQL.
func (store *PostgresStore) ListPolicyNames(ctx context.Context) ([]string, error) {
if !store.configured {
return nil, fmt.Errorf("store not configured")
}
var names []string
rows, err := store.db.QueryContext(ctx, "SELECT name FROM policies")
if err != nil {
return nil, fmt.Errorf("failed to query policy names: %w", err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, fmt.Errorf("failed to scan policy name: %w", err)
}
names = append(names, name)
}
return names, nil
}
// CreatePolicy creates a new IAM policy in PostgreSQL
func (store *PostgresStore) CreatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
if !store.configured {

View File

@@ -236,6 +236,10 @@ func (s *PropagatingCredentialStore) DeletePolicy(ctx context.Context, name stri
return nil
}
func (s *PropagatingCredentialStore) ListPolicyNames(ctx context.Context) ([]string, error) {
return s.CredentialStore.ListPolicyNames(ctx)
}
func (s *PropagatingCredentialStore) CreatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
if pm, ok := s.CredentialStore.(PolicyManager); ok {
if err := pm.CreatePolicy(ctx, name, document); err != nil {