155 lines
5.6 KiB
Go
155 lines
5.6 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package acl
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/nomad/api"
|
|
"github.com/hashicorp/nomad/e2e/e2eutil"
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
// testACLRole tests basic functionality of ACL roles when used for
|
|
// authorization. It also performs some basic token and policy tests due to the
|
|
// coupling between the ACL objects.
|
|
func testACLRole(t *testing.T) {
|
|
|
|
nomadClient := e2eutil.NomadClient(t)
|
|
|
|
// Create and defer the Cleanup process. This is used to remove all
|
|
// resources created by this test and covers situations where the test
|
|
// fails or during normal running.
|
|
cleanUpProcess := NewCleanup()
|
|
defer cleanUpProcess.Run(t, nomadClient)
|
|
|
|
// An ACL role must reference an ACL policy that is stored in state. Ensure
|
|
// this behaviour by attempting to create a role that links to a policy
|
|
// that does not exist.
|
|
invalidRole := api.ACLRole{
|
|
Name: "e2e-acl-" + uuid.Short(),
|
|
Description: "E2E ACL Role Testing",
|
|
Policies: []*api.ACLRolePolicyLink{{Name: "404-not-found"}},
|
|
}
|
|
aclRoleCreateResp, _, err := nomadClient.ACLRoles().Create(&invalidRole, nil)
|
|
must.ErrorContains(t, err, "cannot find policy 404-not-found")
|
|
must.Nil(t, aclRoleCreateResp)
|
|
|
|
// Create a custom namespace to test along with the default.
|
|
ns := api.Namespace{
|
|
Name: "e2e-acl-" + uuid.Short(),
|
|
Description: "E2E ACL Role Testing",
|
|
}
|
|
_, err = nomadClient.Namespaces().Register(&ns, nil)
|
|
must.NoError(t, err)
|
|
|
|
cleanUpProcess.Add(ns.Name, NamespaceTestResourceType)
|
|
|
|
// Create an ACL policy which will be used to link from the role. This
|
|
// policy grants read access to our custom namespace.
|
|
customNamespacePolicy := api.ACLPolicy{
|
|
Name: "e2e-acl-" + uuid.Short(),
|
|
Description: "E2E ACL Role Testing",
|
|
Rules: fmt.Sprintf(`namespace %q {policy = "read"}`, ns.Name),
|
|
}
|
|
_, err = nomadClient.ACLPolicies().Upsert(&customNamespacePolicy, nil)
|
|
must.NoError(t, err)
|
|
|
|
cleanUpProcess.Add(customNamespacePolicy.Name, ACLPolicyTestResourceType)
|
|
|
|
// Create a valid role with a link to the previously created policy.
|
|
validRole := api.ACLRole{
|
|
Name: "e2e-acl-" + uuid.Short(),
|
|
Description: "E2E ACL Role Testing",
|
|
Policies: []*api.ACLRolePolicyLink{{Name: customNamespacePolicy.Name}},
|
|
}
|
|
aclRoleCreateResp, _, err = nomadClient.ACLRoles().Create(&validRole, nil)
|
|
must.NoError(t, err)
|
|
must.NotNil(t, aclRoleCreateResp)
|
|
must.NotEq(t, "", aclRoleCreateResp.ID)
|
|
must.Eq(t, validRole.Name, aclRoleCreateResp.Name)
|
|
|
|
cleanUpProcess.Add(aclRoleCreateResp.ID, ACLRoleTestResourceType)
|
|
|
|
// Perform a role listing and check we have the expected entries.
|
|
aclRoleListResp, _, err := nomadClient.ACLRoles().List(nil)
|
|
must.NoError(t, err)
|
|
must.Len(t, 1, aclRoleListResp)
|
|
must.Eq(t, aclRoleCreateResp.ID, aclRoleListResp[0].ID)
|
|
|
|
// Create our ACL token which is linked to the created ACL role.
|
|
token := api.ACLToken{
|
|
Name: "e2e-acl-" + uuid.Short(),
|
|
Type: "client",
|
|
Roles: []*api.ACLTokenRoleLink{{ID: aclRoleCreateResp.ID}},
|
|
}
|
|
aclTokenCreateResp, _, err := nomadClient.ACLTokens().Create(&token, nil)
|
|
must.NoError(t, err)
|
|
must.NotNil(t, aclTokenCreateResp)
|
|
|
|
cleanUpProcess.Add(aclTokenCreateResp.AccessorID, ACLTokenTestResourceType)
|
|
|
|
// Attempt two job listings against the two available namespaces. The token
|
|
// only has access to the custom namespace, so the default should return an
|
|
// error.
|
|
customNSQueryMeta := api.QueryOptions{Namespace: ns.Name, AuthToken: aclTokenCreateResp.SecretID}
|
|
defaultNSQueryMeta := api.QueryOptions{Namespace: "default", AuthToken: aclTokenCreateResp.SecretID}
|
|
|
|
_, _, err = nomadClient.Jobs().List(&customNSQueryMeta)
|
|
must.NoError(t, err)
|
|
|
|
_, _, err = nomadClient.Jobs().List(&defaultNSQueryMeta)
|
|
must.ErrorContains(t, err, "Permission denied")
|
|
|
|
// Create an ACL policy which grants read access to the default namespace.
|
|
defaultNamespacePolicy := api.ACLPolicy{
|
|
Name: "e2e-acl-" + uuid.Short(),
|
|
Description: "E2E ACL Role Testing",
|
|
Rules: `namespace "default" {policy = "read"}`,
|
|
}
|
|
_, err = nomadClient.ACLPolicies().Upsert(&defaultNamespacePolicy, nil)
|
|
must.NoError(t, err)
|
|
|
|
cleanUpProcess.Add(defaultNamespacePolicy.Name, ACLPolicyTestResourceType)
|
|
|
|
// Update the ACL role to include the new ACL policy that allows read
|
|
// access to the default namespace.
|
|
aclRoleCreateResp.Policies = append(aclRoleCreateResp.Policies, &api.ACLRolePolicyLink{
|
|
Name: defaultNamespacePolicy.Name,
|
|
})
|
|
aclRoleUpdateResp, _, err := nomadClient.ACLRoles().Update(aclRoleCreateResp, nil)
|
|
must.NoError(t, err)
|
|
must.Eq(t, aclRoleCreateResp.ID, aclRoleUpdateResp.ID)
|
|
must.Len(t, 2, aclRoleUpdateResp.Policies)
|
|
|
|
// Try listing the jobs in the default namespace again to ensure we now
|
|
// have permission due to the updated role.
|
|
_, _, err = nomadClient.Jobs().List(&defaultNSQueryMeta)
|
|
must.NoError(t, err)
|
|
|
|
// Delete a policy from under the role.
|
|
_, err = nomadClient.ACLPolicies().Delete(defaultNamespacePolicy.Name, nil)
|
|
must.NoError(t, err)
|
|
|
|
cleanUpProcess.Remove(defaultNamespacePolicy.Name, ACLPolicyTestResourceType)
|
|
|
|
// The permission to list the job in the default namespace should now be
|
|
// revoked.
|
|
_, _, err = nomadClient.Jobs().List(&defaultNSQueryMeta)
|
|
must.ErrorContains(t, err, "Permission denied")
|
|
|
|
// Delete the ACL role.
|
|
_, err = nomadClient.ACLRoles().Delete(aclRoleUpdateResp.ID, nil)
|
|
must.NoError(t, err)
|
|
|
|
cleanUpProcess.Remove(aclRoleUpdateResp.ID, ACLRoleTestResourceType)
|
|
|
|
// We should now not be able to list jobs in the custom namespace either as
|
|
// the token does not have any permissions.
|
|
_, _, err = nomadClient.Jobs().List(&customNSQueryMeta)
|
|
must.ErrorContains(t, err, "Permission denied")
|
|
}
|