mirror of
https://github.com/minio/minio.git
synced 2025-07-26 00:40:08 -04:00
Add tests for Access Management Plugin (#14909)
This commit is contained in:
parent
dc99f4a7a3
commit
4629abd5a2
11
.github/workflows/iam-integrations.yaml
vendored
11
.github/workflows/iam-integrations.yaml
vendored
@ -108,6 +108,17 @@ jobs:
|
|||||||
sudo sysctl net.ipv6.conf.all.disable_ipv6=0
|
sudo sysctl net.ipv6.conf.all.disable_ipv6=0
|
||||||
sudo sysctl net.ipv6.conf.default.disable_ipv6=0
|
sudo sysctl net.ipv6.conf.default.disable_ipv6=0
|
||||||
make test-iam
|
make test-iam
|
||||||
|
- name: Test with Access Management Plugin enabled
|
||||||
|
env:
|
||||||
|
LDAP_TEST_SERVER: ${{ matrix.ldap }}
|
||||||
|
ETCD_SERVER: ${{ matrix.etcd }}
|
||||||
|
OPENID_TEST_SERVER: ${{ matrix.openid }}
|
||||||
|
POLICY_PLUGIN_ENDPOINT: "http://127.0.0.1:8080"
|
||||||
|
run: |
|
||||||
|
sudo sysctl net.ipv6.conf.all.disable_ipv6=0
|
||||||
|
sudo sysctl net.ipv6.conf.default.disable_ipv6=0
|
||||||
|
go run docs/iam/access-manager-plugin.go &
|
||||||
|
make test-iam
|
||||||
- name: Test LDAP for automatic site replication
|
- name: Test LDAP for automatic site replication
|
||||||
if: matrix.ldap == 'localhost:389'
|
if: matrix.ldap == 'localhost:389'
|
||||||
run: |
|
run: |
|
||||||
|
@ -97,6 +97,29 @@ func (s *TestSuiteIAM) iamSetup(c *check) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List of all IAM test suites (i.e. test server configuration combinations)
|
||||||
|
// common to tests.
|
||||||
|
var iamTestSuites = func() []*TestSuiteIAM {
|
||||||
|
baseTestCases := []TestSuiteCommon{
|
||||||
|
// Init and run test on FS backend with signature v4.
|
||||||
|
{serverType: "FS", signer: signerV4},
|
||||||
|
// Init and run test on FS backend, with tls enabled.
|
||||||
|
{serverType: "FS", signer: signerV4, secure: true},
|
||||||
|
// Init and run test on Erasure backend.
|
||||||
|
{serverType: "Erasure", signer: signerV4},
|
||||||
|
// Init and run test on ErasureSet backend.
|
||||||
|
{serverType: "ErasureSet", signer: signerV4},
|
||||||
|
}
|
||||||
|
testCases := []*TestSuiteIAM{}
|
||||||
|
for _, bt := range baseTestCases {
|
||||||
|
testCases = append(testCases,
|
||||||
|
newTestSuiteIAM(bt, false),
|
||||||
|
newTestSuiteIAM(bt, true),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return testCases
|
||||||
|
}()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EnvTestEtcdBackend = "ETCD_SERVER"
|
EnvTestEtcdBackend = "ETCD_SERVER"
|
||||||
)
|
)
|
||||||
@ -166,30 +189,9 @@ func (s *TestSuiteIAM) getUserClient(c *check, accessKey, secretKey, sessionToke
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIAMInternalIDPServerSuite(t *testing.T) {
|
func TestIAMInternalIDPServerSuite(t *testing.T) {
|
||||||
baseTestCases := []TestSuiteCommon{
|
for i, testCase := range iamTestSuites {
|
||||||
// Init and run test on FS backend with signature v4.
|
|
||||||
{serverType: "FS", signer: signerV4},
|
|
||||||
// Init and run test on FS backend, with tls enabled.
|
|
||||||
{serverType: "FS", signer: signerV4, secure: true},
|
|
||||||
// Init and run test on Erasure backend.
|
|
||||||
{serverType: "Erasure", signer: signerV4},
|
|
||||||
// Init and run test on ErasureSet backend.
|
|
||||||
{serverType: "ErasureSet", signer: signerV4},
|
|
||||||
}
|
|
||||||
testCases := []*TestSuiteIAM{}
|
|
||||||
for _, bt := range baseTestCases {
|
|
||||||
testCases = append(testCases,
|
|
||||||
newTestSuiteIAM(bt, false),
|
|
||||||
newTestSuiteIAM(bt, true),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for i, testCase := range testCases {
|
|
||||||
etcdStr := ""
|
|
||||||
if testCase.withEtcdBackend {
|
|
||||||
etcdStr = " (with etcd backend)"
|
|
||||||
}
|
|
||||||
t.Run(
|
t.Run(
|
||||||
fmt.Sprintf("Test: %d, ServerType: %s%s", i+1, testCase.serverType, etcdStr),
|
fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
|
||||||
func(t *testing.T) {
|
func(t *testing.T) {
|
||||||
suite := testCase
|
suite := testCase
|
||||||
c := &check{t, testCase.serverType}
|
c := &check{t, testCase.serverType}
|
||||||
@ -973,6 +975,166 @@ func (s *TestSuiteIAM) TestServiceAccountOpsByAdmin(c *check) {
|
|||||||
c.assertSvcAccDeletion(ctx, s, s.adm, accessKey, bucket)
|
c.assertSvcAccDeletion(ctx, s, s.adm, accessKey, bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TestSuiteIAM) SetUpAccMgmtPlugin(c *check) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
pluginEndpoint := os.Getenv("POLICY_PLUGIN_ENDPOINT")
|
||||||
|
if pluginEndpoint == "" {
|
||||||
|
c.Skip("POLICY_PLUGIN_ENDPOINT not given - skipping.")
|
||||||
|
}
|
||||||
|
|
||||||
|
configCmds := []string{
|
||||||
|
"policy_plugin",
|
||||||
|
"url=" + pluginEndpoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := s.adm.SetConfigKV(ctx, strings.Join(configCmds, " "))
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("unable to setup access management plugin for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.RestartIAMSuite(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestIAM_AMPInternalIDPServerSuite - tests for access management plugin
|
||||||
|
func TestIAM_AMPInternalIDPServerSuite(t *testing.T) {
|
||||||
|
for i, testCase := range iamTestSuites {
|
||||||
|
t.Run(
|
||||||
|
fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
|
||||||
|
func(t *testing.T) {
|
||||||
|
suite := testCase
|
||||||
|
c := &check{t, testCase.serverType}
|
||||||
|
|
||||||
|
suite.SetUpSuite(c)
|
||||||
|
defer suite.TearDownSuite(c)
|
||||||
|
|
||||||
|
suite.SetUpAccMgmtPlugin(c)
|
||||||
|
|
||||||
|
suite.TestAccMgmtPlugin(c)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAccMgmtPlugin - this test assumes that the access-management-plugin is
|
||||||
|
// the same as the example in `docs/iam/access-manager-plugin.go` -
|
||||||
|
// specifically, it denies only `s3:Put*` operations on non-root accounts.
|
||||||
|
func (s *TestSuiteIAM) TestAccMgmtPlugin(c *check) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// 0. Check that owner is able to make-bucket.
|
||||||
|
bucket := getRandomBucketName()
|
||||||
|
err := s.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("bucket creat error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Create a user.
|
||||||
|
accessKey, secretKey := mustGenerateCredentials(c)
|
||||||
|
err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to set user: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Check new user appears in listing
|
||||||
|
usersMap, err := s.adm.ListUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("error listing: %v", err)
|
||||||
|
}
|
||||||
|
v, ok := usersMap[accessKey]
|
||||||
|
if !ok {
|
||||||
|
c.Fatalf("user not listed: %s", accessKey)
|
||||||
|
}
|
||||||
|
c.Assert(v.Status, madmin.AccountEnabled)
|
||||||
|
|
||||||
|
// 3. Check that user is able to make a bucket.
|
||||||
|
client := s.getUserClient(c, accessKey, secretKey, "")
|
||||||
|
err = client.MakeBucket(ctx, getRandomBucketName(), minio.MakeBucketOptions{})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("user not create bucket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.1 check user has access to bucket
|
||||||
|
c.mustListObjects(ctx, client, bucket)
|
||||||
|
|
||||||
|
// 3.2 check that user cannot upload an object.
|
||||||
|
_, err = client.PutObject(ctx, bucket, "objectName", bytes.NewBuffer([]byte("some content")), 12, minio.PutObjectOptions{})
|
||||||
|
if err == nil {
|
||||||
|
c.Fatalf("user was able to upload unexpectedly")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an madmin client with user creds
|
||||||
|
userAdmClient, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
|
||||||
|
Creds: cr.NewStaticV4(accessKey, secretKey, ""),
|
||||||
|
Secure: s.secure,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Err creating user admin client: %v", err)
|
||||||
|
}
|
||||||
|
userAdmClient.SetCustomTransport(s.TestSuiteCommon.client.Transport)
|
||||||
|
|
||||||
|
// Create svc acc
|
||||||
|
cr := c.mustCreateSvcAccount(ctx, accessKey, userAdmClient)
|
||||||
|
|
||||||
|
// 1. Check that svc account appears in listing
|
||||||
|
c.assertSvcAccAppearsInListing(ctx, userAdmClient, accessKey, cr.AccessKey)
|
||||||
|
|
||||||
|
// 2. Check that svc account info can be queried
|
||||||
|
c.assertSvcAccInfoQueryable(ctx, userAdmClient, accessKey, cr.AccessKey, false)
|
||||||
|
|
||||||
|
// 3. Check S3 access
|
||||||
|
c.assertSvcAccS3Access(ctx, s, cr, bucket)
|
||||||
|
|
||||||
|
// Check that session policies do not apply - as policy enforcement is
|
||||||
|
// delegated to plugin.
|
||||||
|
{
|
||||||
|
svcAK, svcSK := mustGenerateCredentials(c)
|
||||||
|
|
||||||
|
// This policy does not allow listing objects.
|
||||||
|
policyBytes := []byte(fmt.Sprintf(`{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:PutObject",
|
||||||
|
"s3:GetObject"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::%s/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, bucket))
|
||||||
|
cr, err := userAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
|
||||||
|
Policy: policyBytes,
|
||||||
|
TargetUser: accessKey,
|
||||||
|
AccessKey: svcAK,
|
||||||
|
SecretKey: svcSK,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Unable to create svc acc: %v", err)
|
||||||
|
}
|
||||||
|
svcClient := s.getUserClient(c, cr.AccessKey, cr.SecretKey, "")
|
||||||
|
// Though the attached policy does not allow listing, it will be
|
||||||
|
// ignored because the plugin allows it.
|
||||||
|
c.mustListObjects(ctx, svcClient, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Check that service account's secret key and account status can be
|
||||||
|
// updated.
|
||||||
|
c.assertSvcAccSecretKeyAndStatusUpdate(ctx, s, userAdmClient, accessKey, bucket)
|
||||||
|
|
||||||
|
// 5. Check that service account can be deleted.
|
||||||
|
c.assertSvcAccDeletion(ctx, s, userAdmClient, accessKey, bucket)
|
||||||
|
|
||||||
|
// 6. Check that service account **can** be created for some other user.
|
||||||
|
// This is possible because of the policy enforced in the plugin.
|
||||||
|
c.mustCreateSvcAccount(ctx, globalActiveCred.AccessKey, userAdmClient)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *check) mustCreateIAMUser(ctx context.Context, admClnt *madmin.AdminClient) madmin.Credentials {
|
func (c *check) mustCreateIAMUser(ctx context.Context, admClnt *madmin.AdminClient) madmin.Credentials {
|
||||||
randUser := mustGetUUID()
|
randUser := mustGetUUID()
|
||||||
randPass := mustGetUUID()
|
randPass := mustGetUUID()
|
||||||
|
@ -1311,29 +1311,6 @@ func (s *TestSuiteIAM) TestOpenIDServiceAccWithRolePolicy(c *check) {
|
|||||||
c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
|
c.assertSvcAccDeletion(ctx, s, userAdmClient, value.AccessKeyID, bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of all IAM test suites (i.e. test server configuration combinations)
|
|
||||||
// common to tests.
|
|
||||||
var iamTestSuites = func() []*TestSuiteIAM {
|
|
||||||
baseTestCases := []TestSuiteCommon{
|
|
||||||
// Init and run test on FS backend with signature v4.
|
|
||||||
{serverType: "FS", signer: signerV4},
|
|
||||||
// Init and run test on FS backend, with tls enabled.
|
|
||||||
{serverType: "FS", signer: signerV4, secure: true},
|
|
||||||
// Init and run test on Erasure backend.
|
|
||||||
{serverType: "Erasure", signer: signerV4},
|
|
||||||
// Init and run test on ErasureSet backend.
|
|
||||||
{serverType: "ErasureSet", signer: signerV4},
|
|
||||||
}
|
|
||||||
testCases := []*TestSuiteIAM{}
|
|
||||||
for _, bt := range baseTestCases {
|
|
||||||
testCases = append(testCases,
|
|
||||||
newTestSuiteIAM(bt, false),
|
|
||||||
newTestSuiteIAM(bt, true),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return testCases
|
|
||||||
}()
|
|
||||||
|
|
||||||
func TestIAMWithOpenIDMultipleConfigsValidation(t *testing.T) {
|
func TestIAMWithOpenIDMultipleConfigsValidation(t *testing.T) {
|
||||||
openIDServer := os.Getenv(EnvTestOpenIDServer)
|
openIDServer := os.Getenv(EnvTestOpenIDServer)
|
||||||
openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
|
openIDServer2 := os.Getenv(EnvTestOpenIDServer2)
|
||||||
|
@ -79,5 +79,6 @@ func mainHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/", mainHandler)
|
http.HandleFunc("/", mainHandler)
|
||||||
|
|
||||||
|
log.Print("Listening on :8080")
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user