Skip to content

Instantly share code, notes, and snippets.

@hansenms
Created June 11, 2024 17:30
Show Gist options
  • Save hansenms/d6992833d8ad5183850479210684221c to your computer and use it in GitHub Desktop.
Save hansenms/d6992833d8ad5183850479210684221c to your computer and use it in GitHub Desktop.
#!/bin/bash
set -euo pipefail
cache_dir="${HOME}/.pim"
mkdir -p "${cache_dir}"
eligible_roles_cache="${cache_dir}/eligible_roles.json"
active_roles_cache="${cache_dir}/active_roles.json"
principalId=""
role_numbers=()
# Commands
command=""
if [ $# -eq 0 ]; then
command="activate"
else
command="$1"
fi
if [ "$command" != "activate" ] && [ "$command" != "deactivate" ]; then
echo "Usage: $0 [activate|deactivate]"
exit 1
fi
update_eligible_roles()
{
az rest --method get --url "https://management.azure.com/providers/Microsoft.Authorization/roleEligibilityScheduleInstances?api-version=2020-10-01" --url-parameters \$filter="asTarget()" | jq -r .value > "${eligible_roles_cache}"
}
update_active_roles()
{
az rest --method get --url "https://management.azure.com/providers/Microsoft.Authorization/roleAssignmentScheduleInstances?api-version=2020-10-01" --url-parameters \$filter="asTarget()" | jq -r .value > "${active_roles_cache}"
}
list_roles() {
cache_file="$1"
num_roles=$(jq length "${cache_file}")
for i in $(seq 0 $((num_roles - 1))); do
role=$(jq -r .[$i].properties.expandedProperties.roleDefinition.displayName "${cache_file}")
scope_name=$(jq -r .[$i].properties.expandedProperties.scope.displayName "${cache_file}")
scope_type=$(jq -r .[$i].properties.expandedProperties.scope.type "${cache_file}")
echo "[${i}] ${role}@${scope_name} (${scope_type})"
done
}
list_eligible_roles() {
list_roles "${eligible_roles_cache}"
}
list_active_roles() {
list_roles "${active_roles_cache}"
}
read_role_numbers() {
read -p "Enter the role numbers to elevate (comma separated): " role_numbers
IFS=',' read -r -a role_numbers <<< "$role_numbers"
}
set_principal() {
if [ -z "$principalId" ]; then
principalId=$(az ad signed-in-user show | jq -r .id)
fi
}
activate_role() {
set_principal
role_number=$1
roleDefinitionId=$(jq -r .[$role_number].properties.expandedProperties.roleDefinition.id "${eligible_roles_cache}")
scope=$(jq -r .[$role_number].properties.expandedProperties.scope.id "${eligible_roles_cache}")
roleDisplayName=$(jq -r .[$role_number].properties.expandedProperties.roleDefinition.displayName "${eligible_roles_cache}")
scopeDisplayName=$(jq -r .[$role_number].properties.expandedProperties.scope.displayName "${eligible_roles_cache}")
linkedRoleEligibilityScheduleId=$(jq -r .[$role_number].properties.roleEligibilityScheduleId "${eligible_roles_cache}")
# Start time is now
startDateTime=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
# GUID for the request
roleAssignmentScheduleRequestName=$(cat /proc/sys/kernel/random/uuid)
json_body=$(cat <<EOF
{
"properties": {
"principalId": "$principalId",
"roleDefinitionId": "$roleDefinitionId",
"linkedRoleEligibilityScheduleId": "$linkedRoleEligibilityScheduleId",
"requestType": "SelfActivate",
"scheduleInfo": {
"startDateTime": "$startDateTime",
"expiration": {
"type": "AfterDuration",
"endDateTime": null,
"duration": "PT8H"
}
},
"justification": "I need it"
}
}
EOF
)
echo "Activating role ${roleDisplayName}@${scopeDisplayName}"
# Unfortunately, az rest gets clever and can get a token for the wrong principal, we help it a bit
token=$(az account get-access-token --query accessToken -o tsv)
az rest --headers Authorization="Bearer $token" --method put --url "https://management.azure.com/${scope}/providers/Microsoft.Authorization/roleAssignmentScheduleRequests/${roleAssignmentScheduleRequestName}?api-version=2020-10-01" --body "$json_body" > /dev/null
}
deactivate_role() {
set_principal
role_number=$1
roleDefinitionId=$(jq -r .[$role_number].properties.expandedProperties.roleDefinition.id "${active_roles_cache}")
scope=$(jq -r .[$role_number].properties.expandedProperties.scope.id "${active_roles_cache}")
requestName=$(jq -r .[$role_number].name "${active_roles_cache}")
roleDisplayName=$(jq -r .[$role_number].properties.expandedProperties.roleDefinition.displayName "${active_roles_cache}")
scopeDisplayName=$(jq -r .[$role_number].properties.expandedProperties.scope.displayName "${active_roles_cache}")
json_body=$(cat <<EOF
{
"Properties": {
"RoleDefinitionId": "$roleDefinitionId",
"PrincipalId": "$principalId",
"RequestType": "SelfDeactivate"
}
}
EOF
)
echo "Deactivating role ${roleDisplayName}@${scopeDisplayName}"
# Unfortunately, az rest gets clever and can get a token for the wrong principal, we help it a bit
token=$(az account get-access-token --query accessToken -o tsv)
az rest --headers Authorization="Bearer $token" --method put --url "https://management.azure.com/${scope}/providers/Microsoft.Authorization/roleAssignmentScheduleRequests/${requestName}?api-version=2020-10-01" --body "$json_body" > /dev/null
}
if [ "$command" == "activate" ]; then
update_eligible_roles
list_eligible_roles
read_role_numbers
for role_number in "${role_numbers[@]}"; do
activate_role "${role_number}"
done
elif [ "$command" == "deactivate" ]; then
update_active_roles
# If there are no active roles, then there is nothing to deactivate
active_roles=$(jq length "${active_roles_cache}")
if [ $active_roles -eq 0 ]; then
echo "No active roles to deactivate"
exit 0
fi
list_active_roles
read_role_numbers
for role_number in "${role_numbers[@]}"; do
deactivate_role "${role_number}"
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment