Now What Were Those Permissions for This User Again?

If you have had occasion to try out the new IAM (Identity and Access Management) rollout for Chef Automate, you are probably eager to connect projects, policies, users and teams to give your organization the fine-grained separation of control vital to your business.

If you happen to use local users and teams (and I know that some of you are using LDAP or SAML — sorry!), here is a tip to help you sort out the permissions a given user actually has. Consider how this could be complicated:

  • You can add users to policies.
  • You can add users to local teams.
  • You can add teams to policies.
  • You can add (via wildcard) all users or all local users.
  • You can add (via wildcard) all teams or all local teams.

You, of course, just want to do your job creating a new local user and giving them the right permissions. Say you add them on team t1, team t2, and policies p1, p2, and p3. How would you ask the system to confirm what their aggregate permissions are? Here is a short shell script to answer that question for you.

First, let’s take a look at a sample run (I have colorized and emboldened for clarity):

$ a2policies bob
Checking user:local:bob...
Checking team:local:auditors...
Checking team:local:viewers...
Checking team:local:deployment...

Interpreting the above results, the script first checks local user “Bob”. The results indicate that Bob is directly a member of the project_1-1-project-owners policy and indirectly (via wildcard) of the foo-project-viewers policy. Next, the script checks each of the teams that Bob belongs to in turn. The results show that Bob is a member of a variety of policies due to (a) being a member of a team that is directly in a policy, (b) just being a member of a local team (team:local:*) and (c) being a member of any kind of team (team:*).

If that is useful, here is how to set up that command.

  1. Make sure you have jq ( and curl available.
  2. Get an admin token (export TOK=`chef-automate iam token create myAdminToken --admin`). Note that the chef-automate command is only available on the Automate server. For more on tokens see
  3. Specify your Automate host (export TARGET_HOST=
  4. Put this Bash shell function in your profile or rc file.
a2policies() {
local user_and_teams=("$1")
local user_id
user_id=$(curl -sSkH "api-token: $TOK" "$TARGET_HOST/apis/iam/v2/users/$1" | jq -cr '.user.membership_id')
if [[ $user_id != "null" ]]; then
teams=$(curl -sSkH "api-token: $TOK" "$TARGET_HOST/apis/iam/v2/users/$user_id/teams" | jq -r '.teams[] | .id')
user_and_teams=("$1" ${teams[@]})
local resourceType="user"
for resource in "${user_and_teams[@]}"
printf "\nChecking %s:local:%s...\n" "$resourceType" "$resource"
curl -sSkH "api-token: $TOK" -H "" "$TARGET_HOST/apis/iam/v2/policies" | \
jq -cr --arg name "$resourceType:local:$resource" \
--arg allLocal "$resourceType:local:*" \
--arg allType "$resourceType:*" \
'.policies[] |
select (.members | contains([$name]) or contains([$allLocal]) or contains([$allType]) or (index("*") != null)) |
.id, .members'

Comments on this or suggestions to make it even more useful? Post to the automate2_0 slack channel in the Chef Community Slack!

Michael Sorens

Michael Sorens is a Chef senior software engineer working on ChefAutomate, and is passionate about productivity, process, and quality. He enjoys spreading the seeds of good design wherever possible, having written over 100 articles, more than a dozen wallcharts, and posted in excess of 200 answers on StackOverflow.