From Scratch: Permissions
Once we have our groups and users set up from our external identity provider we can move on to defining what permissions they should have. This is mostly straightforward, but we'll have to take a few detours along the way because of how groups work with the Google Workspace IDP.
Permission Sets
The first thing we have to do is script our permission sets. We will use these to connect IAM policies to our IDP groups. This will all be done in CDKTF.
const set = new SsoadminPermissionSet(scope, `${name}-admin`, {
name: `${name}-admin`,
instanceArn: arnId,
});
There's not a lot to this. The ARN we are using here for the instanceArn
actually comes from the same DataAwsSsoadminInstances
we used to get the storeId
before.
Policies
Now that we have our admin permission set, we have to actually give it an admin policy.
new SsoadminManagedPolicyAttachment(scope, `${name}-admin-policy`, {
instanceArn: arnId,
managedPolicyArn: "arn:aws:iam::aws:policy/AdministratorAccess",
permissionSetArn: set.arn,
});
The policy here is just the AWS managed policy that comes with every account. We're ready to deploy at this point, so we need to go back into our AWS console, and reactivate the root user's access key. Remember, the last time we used it we deactivated it as soon as we were done, and we're going to do the same thing here.
With the access key active again, we can go ahead and cdktf deploy
our stack, and we should see two more resources get created. Once it's done we go back into the console and turn off the access keys again.
Group Assignment
With these new permissions we should be all set now to assign our groups those permissions and be on our way, but this is where we hit our first snag. We need to go into the identity center console as root and assign the group to our AWS account along with the admin permission set we just made, which we can do, but there's a problem. Because of how we had to make the groups in identity center, we aren't able to assign users to the group in the console. It has to be scripted. The root user shouldn't do this, though, because managing permissions at this level would mean people would have to be logging into root all the time, which is a big problem. Instead, what I'm going to do instead is assign myself to the AWS account. My user was brought over automatically through the identity provider, and I can set all that up in the console easily.
Switching Users
With that set up, I now have my user assigned as an admin in the AWS account. Now it's time to configure AWS CLI with my sso. With that done, we're going to make a new stack that uses the admin profile to allocate infrastructure.
Account Assignment
Now we're ready to assign the group to the AWS account, and add any users we want along the way. Since we'll be doing this as an admin user, we'll need to make a new CDKTF stack, and deploy it using the admin profile after logging in using aws sso login
. In my case, I made an admin
profile and configured the aws cli with it.
The first thing we'll add to the new stack is going to be the account assignment that adds the group to the AWS account with admin permissions.
new SsoadminAccountAssignment(scope, `${name}-ga-admin`, {
provider: config.provider,
principalType: "GROUP",
targetType: "AWS_ACCOUNT",
targetId: config.caller.accountId,
permissionSetArn: config.identityCenter.permissions.admin.arn,
instanceArn: config.storeArn,
principalId: config.identityCenter.groups.admin.groupId,
});
At this point the group is set up and ready to use. We can now go ahead and add some users to it.
const juser = new DataAwsIdentitystoreUser(scope, `${name}-iu-joseph`, {
identityStoreId: config.storeId,
alternateIdentifier: {
uniqueAttribute: {
attributePath: "UserName",
attributeValue: "joseph@awsdemo.com",
},
},
});
new IdentitystoreGroupMembership(scope, `${name}-gm-joseph`, {
identityStoreId: config.storeId,
groupId: config.identityCenter.groups.admin.groupId,
memberId: juser.userId,
});
Remember the users are automatically syncronized from our external identity provider, so we won't be making a user. Instead, we just need to grab the one we already have. In my case I found my own account by username. There are other options too, but this one is pretty straightforward. From this point it's just a matter of creating a membership for the user to belong to the group.
Separate Stacks
We started off by building some resources using root and then made a separate stack for things an admin can then do. However, the interesting thing about this approach is that once you have an admin that can log into the system, they also have enough permissions to do everything in the first stack we made. We used the root user to get us just far enough in our IaC build out that our admin users could take over. From this point on, we won't be needing the root user anymore, so we can go ahead and delete the access key it had.
As always, if you are interested in how everything ties together, you can take a look at the how to cloud repository.