Created
June 11, 2024 17:30
-
-
Save hansenms/d6992833d8ad5183850479210684221c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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