fix: IAM import/export: remove sts group handling (#19422)

There are no separate STS group mappings to be handled.

Also add tests for basic import/export sanity.
This commit is contained in:
Aditya Manthramurthy 2024-04-05 20:13:35 -07:00 committed by GitHub
parent 91f91d8f47
commit 8ff2a7a2b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 177 additions and 55 deletions

View File

@ -1763,7 +1763,6 @@ const (
userPolicyMappingsFile = "user_mappings.json"
groupPolicyMappingsFile = "group_mappings.json"
stsUserPolicyMappingsFile = "stsuser_mappings.json"
stsGroupPolicyMappingsFile = "stsgroup_mappings.json"
iamAssetsDir = "iam-assets"
)
@ -1813,7 +1812,6 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
userPolicyMappingsFile,
groupPolicyMappingsFile,
stsUserPolicyMappingsFile,
stsGroupPolicyMappingsFile,
}
for _, f := range iamFiles {
iamFile := pathJoin(iamAssetsDir, f)
@ -1985,22 +1983,6 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
return
}
case stsGroupPolicyMappingsFile:
groupPolicyMap := xsync.NewMapOf[string, MappedPolicy]()
err := globalIAMSys.store.loadMappedPolicies(ctx, stsUser, true, groupPolicyMap)
if err != nil {
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
return
}
grpPolData, err := json.Marshal(mappedPoliciesToMap(groupPolicyMap))
if err != nil {
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
return
}
if err = rawDataFn(bytes.NewReader(grpPolData), iamFile, len(grpPolData)); err != nil {
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
return
}
}
}
}
@ -2391,35 +2373,6 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
}
}
}
// import sts group policy mappings
{
f, err := zr.Open(pathJoin(iamAssetsDir, stsGroupPolicyMappingsFile))
switch {
case errors.Is(err, os.ErrNotExist):
case err != nil:
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, stsGroupPolicyMappingsFile, ""), r.URL)
return
default:
defer f.Close()
var grpPolicyMap map[string]MappedPolicy
data, err := io.ReadAll(f)
if err != nil {
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, stsGroupPolicyMappingsFile, ""), r.URL)
return
}
if err = json.Unmarshal(data, &grpPolicyMap); err != nil {
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, stsGroupPolicyMappingsFile, ""), r.URL)
return
}
for g, pm := range grpPolicyMap {
if _, err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, unknownIAMUserType, true); err != nil {
writeErrorResponseJSON(ctx, w, importError(ctx, err, stsGroupPolicyMappingsFile, g), r.URL)
return
}
}
}
}
}
func addExpirationToCondValues(exp *time.Time, condValues map[string][]string) {

View File

@ -18,9 +18,12 @@
package cmd
import (
"bytes"
"context"
"fmt"
"io"
"os"
"reflect"
"strings"
"testing"
"time"
@ -752,6 +755,172 @@ func TestIAMWithLDAPNonNormalizedBaseDNConfigServerSuite(t *testing.T) {
}
}
func TestIAMExportImportWithLDAP(t *testing.T) {
for i, testCase := range iamTestSuites {
t.Run(
fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
func(t *testing.T) {
c := &check{t, testCase.serverType}
suite := testCase
ldapServer := os.Getenv(EnvTestLDAPServer)
if ldapServer == "" {
c.Skipf("Skipping LDAP test as no LDAP server is provided via %s", EnvTestLDAPServer)
}
iamTestContentCases := []iamTestContent{
{
policies: map[string][]byte{
"mypolicy": []byte(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject","s3:ListBucket","s3:PutObject"],"Resource":["arn:aws:s3:::mybucket/*"]}]}`),
},
ldapUserPolicyMappings: map[string][]string{
"uid=dillon,ou=people,ou=swengg,dc=min,dc=io": {"mypolicy"},
"uid=liza,ou=people,ou=swengg,dc=min,dc=io": {"consoleAdmin"},
},
ldapGroupPolicyMappings: map[string][]string{
"cn=projectb,ou=groups,ou=swengg,dc=min,dc=io": {"mypolicy"},
"cn=projecta,ou=groups,ou=swengg,dc=min,dc=io": {"consoleAdmin"},
},
},
}
for caseNum, content := range iamTestContentCases {
suite.SetUpSuite(c)
suite.SetUpLDAP(c, ldapServer)
exportedContent := suite.TestIAMExport(c, caseNum, content)
suite.TearDownSuite(c)
suite.SetUpSuite(c)
suite.SetUpLDAP(c, ldapServer)
suite.TestIAMImport(c, exportedContent, caseNum, content)
suite.TearDownSuite(c)
}
},
)
}
}
type iamTestContent struct {
policies map[string][]byte
ldapUserPolicyMappings map[string][]string
ldapGroupPolicyMappings map[string][]string
}
func (s *TestSuiteIAM) TestIAMExport(c *check, caseNum int, content iamTestContent) []byte {
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
defer cancel()
for policy, policyBytes := range content.policies {
err := s.adm.AddCannedPolicy(ctx, policy, policyBytes)
if err != nil {
c.Fatalf("export %d: policy add error: %v", caseNum, err)
}
}
for userDN, policies := range content.ldapUserPolicyMappings {
_, err := s.adm.AttachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
Policies: policies,
User: userDN,
})
if err != nil {
c.Fatalf("export %d: Unable to attach policy: %v", caseNum, err)
}
}
for groupDN, policies := range content.ldapGroupPolicyMappings {
_, err := s.adm.AttachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
Policies: policies,
Group: groupDN,
})
if err != nil {
c.Fatalf("export %d: Unable to attach group policy: %v", caseNum, err)
}
}
contentReader, err := s.adm.ExportIAM(ctx)
if err != nil {
c.Fatalf("export %d: Unable to export IAM: %v", caseNum, err)
}
defer contentReader.Close()
expContent, err := io.ReadAll(contentReader)
if err != nil {
c.Fatalf("export %d: Unable to read exported content: %v", caseNum, err)
}
return expContent
}
type dummyCloser struct {
io.Reader
}
func (d dummyCloser) Close() error { return nil }
func (s *TestSuiteIAM) TestIAMImport(c *check, exportedContent []byte, caseNum int, content iamTestContent) {
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
defer cancel()
dummyCloser := dummyCloser{bytes.NewReader(exportedContent)}
err := s.adm.ImportIAM(ctx, dummyCloser)
if err != nil {
c.Fatalf("import %d: Unable to import IAM: %v", caseNum, err)
}
gotContent := iamTestContent{
policies: make(map[string][]byte),
ldapUserPolicyMappings: make(map[string][]string),
ldapGroupPolicyMappings: make(map[string][]string),
}
policyContentMap, err := s.adm.ListCannedPolicies(ctx)
if err != nil {
c.Fatalf("import %d: Unable to list policies: %v", caseNum, err)
}
defaultCannedPolicies := set.CreateStringSet("consoleAdmin", "readwrite", "readonly",
"diagnostics", "writeonly")
for policy, policyBytes := range policyContentMap {
if defaultCannedPolicies.Contains(policy) {
continue
}
gotContent.policies[policy] = policyBytes
}
policyQueryRes, err := s.adm.GetLDAPPolicyEntities(ctx, madmin.PolicyEntitiesQuery{})
if err != nil {
c.Fatalf("import %d: Unable to get policy entities: %v", caseNum, err)
}
for _, entity := range policyQueryRes.PolicyMappings {
m := gotContent.ldapUserPolicyMappings
for _, user := range entity.Users {
m[user] = append(m[user], entity.Policy)
}
m = gotContent.ldapGroupPolicyMappings
for _, group := range entity.Groups {
m[group] = append(m[group], entity.Policy)
}
}
{
// We don't compare the values of the canned policies because server is
// re-encoding them. (FIXME?)
for k := range content.policies {
content.policies[k] = nil
gotContent.policies[k] = nil
}
if !reflect.DeepEqual(content.policies, gotContent.policies) {
c.Fatalf("import %d: policies mismatch: expected: %v, got: %v", caseNum, content.policies, gotContent.policies)
}
}
if !reflect.DeepEqual(content.ldapUserPolicyMappings, gotContent.ldapUserPolicyMappings) {
c.Fatalf("import %d: user policy mappings mismatch: expected: %v, got: %v", caseNum, content.ldapUserPolicyMappings, gotContent.ldapUserPolicyMappings)
}
if !reflect.DeepEqual(content.ldapGroupPolicyMappings, gotContent.ldapGroupPolicyMappings) {
c.Fatalf("import %d: group policy mappings mismatch: expected: %v, got: %v", caseNum, content.ldapGroupPolicyMappings, gotContent.ldapGroupPolicyMappings)
}
}
func (s *TestSuiteIAM) TestLDAPSTS(c *check) {
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
defer cancel()