Azure CLI SP creation w/ API permissions - azure-active-directory

I'm trying to write a simple script to create an SP that is assigned some Microsoft Graph API permissions. I think what I need to do is create an SP with a Contributor role, then assign it the API permissions I need from Microsoft Graph API, and then grant admin consent. It does run to completion, however then when I look in the portal admin consent hasn't been granted, and when I then try to assign manually, I get the following:
Grant consent failed with error: Claim is invalid: 204e0828-b5ca-4ad8-b9f3-f32a958e7cc4 does not exist on resource application 00000003-0000-0000-c000-000000000000. [zPYKlPo0GJHRzGclFADr9k]
Here's the script, any suggestions are welcome:
#!/bin/bash
## Usage: ./setup-sp.sh <app-name>
set -eou pipefail
getPermissionId () {
# $1 = name of permission, e.g. User.ReadWrite.All
echo `az ad sp list \
--query "[?appDisplayName=='Microsoft Graph'].{permissions:oauth2Permissions}[0].permissions[?value=='$1'].id" \
--all \
--output tsv`
}
APP_NAME=$1
echo "Getting subscription ID"
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
echo "Subscription ID is: $SUBSCRIPTION_ID"
echo "Creating an App Registration and associated Service Principal"
SP=$(az ad sp create-for-rbac --role Contributor --name $APP_NAME --scopes /subscriptions/$SUBSCRIPTION_ID)
echo "The following is your Service Principal credentials, store them securely!"
echo $SP
APP_ID=$(echo $SP | jq -r .appId)
echo "Application ID is: $APP_ID"
# Microsoft Graph API Id
API_ID="00000003-0000-0000-c000-000000000000"
# IDs for various Application Roles
echo "Getting API permission IDs"
USER_READWRITE_ALL_ID=$(getPermissionId User.ReadWrite.All)
GROUP_READWRITE_ALL_ID=$(getPermissionId Group.ReadWrite.All)
APPLICATION_READWRITE_ALL_ID=$(getPermissionId Application.ReadWrite.All)
# Add permissions to SP
echo "Adding API permissions to SP"
az ad app permission add \
--id $APP_ID \
--api $API_ID \
--api-permissions \
$USER_READWRITE_ALL_ID=Role \
$GROUP_READWRITE_ALL_ID=Role \
$APPLICATION_READWRITE_ALL_ID=Role
echo "Granting access for Microsoft Graph API"
az ad app permission grant --id $APP_ID --api $API_ID
echo "Granting admin-consent for API permissions"
az ad app permission admin-consent --id $APP_ID
echo "Done. Check out your SP at: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/$APP_ID"

There were two issues in the code.
First, the code to find the API permission IDs that was based on the query from here https://learn.microsoft.com/en-us/graph/permissions-reference#retrieving-permission-ids was actually returning the ID for AD graph, not Microsoft Graph.
Second, az ad app permission admin-consent is deprecated and the az ad sp permission grant only works for Delegated permissions, not Application permissions (https://github.com/Azure/azure-cli/issues/12137#issuecomment-596567479). The solution is to first pull the Object ID of the SP and Microsoft Graph API, and then use az rest to POST the grant directly. Here's the working copy:
#!/bin/bash
## Usage: ./setup-sp.sh <app-name>
set -eou pipefail
APP_NAME=$1
# Microsoft Graph API Id
API_ID="00000003-0000-0000-c000-000000000000"
USER_READWRITE_ALL_ROLE="User.ReadWrite.All"
GROUP_READWRITE_ALL_ROLE="Group.ReadWrite.All"
APPLICATION_READWRITE_ALL_ROLE="Application.ReadWrite.All"
getPermissionId () {
# $1 = name of permission, e.g. User.ReadWrite.All
echo `az ad sp show --id $API_ID --query "appRoles[?value=='$1'].id" --output tsv`
}
grantPermission () {
# $1 = SP objectId
# $2 = resourceId
# $3 = permissionId
az rest \
--method POST \
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$1/appRoleAssignments" \
--headers '{"Content-Type": "application/json"}' \
--body "{\"principalId\": \"$1\", \"resourceId\": \"$2\", \"appRoleId\": \"$3\"}" \
--only-show-errors
}
echo "Getting subscription ID"
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
echo "Subscription ID is: $SUBSCRIPTION_ID"
echo "Creating an App Registration and associated Service Principal"
SP=$(az ad sp create-for-rbac --role Contributor --name $APP_NAME)
echo "The following is your Service Principal credentials, store them securely!"
echo $SP
APP_ID=$(echo $SP | jq -r .appId)
echo "Application ID is: $APP_ID"
echo "Getting your users' Object ID"
USER_ID=$(az ad signed-in-user show --query objectId --output tsv)
echo "Object ID: $USER_ID"
echo "Adding you as owner of the Service Principal"
az ad app owner add --id $APP_ID --owner-object-id $USER_ID
# IDs for various Application Roles
echo "Getting API permission IDs"
USER_READWRITE_ALL_ID=$(getPermissionId $USER_READWRITE_ALL_ROLE)
GROUP_READWRITE_ALL_ID=$(getPermissionId $GROUP_READWRITE_ALL_ROLE)
APPLICATION_READWRITE_ALL_ID=$(getPermissionId $APPLICATION_READWRITE_ALL_ROLE)
echo "$USER_READWRITE_ALL_ROLE = $USER_READWRITE_ALL_ID"
echo "$GROUP_READWRITE_ALL_ROLE = $GROUP_READWRITE_ALL_ID"
echo "$APPLICATION_READWRITE_ALL_ROLE = $APPLICATION_READWRITE_ALL_ID"
# Add permissions to SP
echo "Adding API permissions to SP"
az ad app permission add \
--id $APP_ID \
--api $API_ID \
--api-permissions \
$USER_READWRITE_ALL_ID=Role \
$GROUP_READWRITE_ALL_ID=Role \
$APPLICATION_READWRITE_ALL_ID=Role
# NOTE: az cli does not have a command to consent for application permissions
# see here: https://github.com/Azure/azure-cli/issues/12137#issuecomment-596567479
# and here: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-approleassignments?view=graph-rest-1.0&tabs=http
echo "Granting consent for API permissions"
APP_OBJECT_ID=$(az ad sp show --id $APP_ID --query "objectId" --output tsv)
API_OBJECT_ID=$(az ad sp show --id $API_ID --query "objectId" --output tsv)
grantPermission $APP_OBJECT_ID $API_OBJECT_ID $USER_READWRITE_ALL_ID
grantPermission $APP_OBJECT_ID $API_OBJECT_ID $GROUP_READWRITE_ALL_ID
grantPermission $APP_OBJECT_ID $API_OBJECT_ID $APPLICATION_READWRITE_ALL_ID
echo "Done. Check out your SP at: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/$APP_ID"

Related

SQL Server and sqlcmd cant insert a new record

I'm using an Ubuntu server with SQL Server installed and fail2ban for securing my services from brute force with some along securities.
So the problem is this: I created a bash script that takes the arguments from fail2ban IP, jail-name etc and creates a record to SQL Server via sqlcmd. When I'm testing the script it works perfectly.
But when it comes to real values and more it takes a wrong turn.
The bash script is this:
${sqlcmd} = full path of sqlcmd
${CMD_SQL} = "${sqlcmd} -S localhost -U randomuser -P randompassword(reading it from a file using grep) -Q "
#...
#code for checking some stuff and creating variables
#...
${CMD_SQL} <<EOF "INSERT INTO ${DB_TABLE} (ip, ports, protocol, jail,hostname, country, rdns, timestamp,failures, loglines) VALUES ('${_ip}', '${_ports}', '${_protocol}', '${_jail}','${_hostname}', '${_country}', '${_rdns}', CURRENT_TIMESTAMP,'${_failures}', '${_loglines}');"
EOF
When the script run from fail2ban service i saw on the logs the real values which it didnt insert them into sql. I tried to run them by myself.
sudo /opt/mssql-tools/bin/sqlcmd -S localhost -U randomuser -P randomPass -Q INSERT INTO dbo.banned (ip, ports, protocol, jail,hostname, country, rdns, timestamp,failures, loglines) VALUES ('12.12.12.12', 'All-ports', 'tcp', 'mssqld','djasserver', 'SA, Saudi Arabia', '', CURRENT_TIMESTAMP,'5', '2022-03-12 04:17:10.20 Logon Login failed for user 'sa'. Reason: Could not find a login matching the name provided. [CLIENT: 12.12.12.12] 2022-03-12 04:17:10.54 Logon Login failed for user 'sa'. Reason: Could not find a login matching the name provided. [CLIENT: 12.12.12.12] 2022-03-12 04:17:10.89 Logon Login failed for user 'sa'. Reason: Could not find a login matching the name provided. [CLIENT: 12.12.12.12] 2022-03-12 04:17:11.22 Logon Login failed for user 'sa'. Reason: Could not find a login matching the name provided. [CLIENT: 12.12.12.12] 2022-03-12 04:17:11.56 Logon Login failed for user 'sa'. Reason: Could not find a login matching the name provided. [CLIENT: 12.12.12.12]');
So at first I got an error:
-bash: syntax error near unexpected token `('
and I thought to myself that the query must be in quotation marks and I added this:
${sqlcmd} = full path of sqlcmd
${CMD_SQL} = "${sqlcmd} -S localhost -U randomuser -P randompassword(reading it from a file using grep) -Q "
#...
#code for checking some stuff and creating variables
#...
${CMD_SQL} <<EOF "\"INSERT INTO ${DB_TABLE} (ip, ports, protocol, jail,hostname, country, rdns, timestamp,failures, loglines) VALUES ('${_ip}', '${_ports}', '${_protocol}', '${_jail}','${_hostname}', '${_country}', '${_rdns}', CURRENT_TIMESTAMP,'${_failures}', '${_loglines}');\""
EOF
I run again the above real values and got this error from SQL:
Msg 102, Level 15, State 1, Server myserver, Line 1
Incorrect syntax near 'sa'.
And I thought okay it probably cannot pass some escape characters it contains.
The question is how do I fix this SQL error? Thanks for any answer.
PS: of course username, password and ips aren't real I changed them for protecting attackers privacy and mine.

Getting Domain for User with DSQuery | DSGet

Using DSQuery and DSGet to get user attributes that are needed to make accounts (not associated with their Windows account). The current command I've got is:
dsquery * -filter "(&(objectCategory=Person)(objectclass=User)(mail=first.last#email.com))" | dsget user -samid -fn -ln -office -email > user.txt
which gets me all the information I need except the domain the user is associated with. There's the attribute in AD called User logon name (pre-Windows 2000) (first box), but as far as I can tell DSGet doesn't return that. I know the DSQuery can get me the groups the user is in but I'm not sure if there's an easy (one-liner) that can get the info needed. Any guidance or help is appreciated.
There is no attribute User logon name (pre-Windows 2000) in Attribute Editor so there is another way we can get the user logon name using distinguish name (DN) and UPN(User logon Name)
please use the below command to get the DN
This is for user
dsquery * -filter "(&(objectCategory=Person)(objectclass=user)(mail=first.last#microsoft.com))" | dsget user "CN=RahulShaw,CN=Users,DC=microsoft,DC=com" -samid -fn -ln -office -email -DN -UPN > Ansuman.txt
This is under Domain Users
dsquery * -filter "(&(objectCategory=Group)(objectclass=group)(mail=first.last#microsoft.com))" | dsget group "CN=Domain Users,CN=Users,DC=microsoft,DC=com" -samid -DN > ipsita.txt

Azure SQL Server ad-admin create ValidationError

When I run the following az-cli commands (as part of a larger script), it fails with the error:
ValidationError: The 'parameters.properties.sid' segment in the url is invalid.
I couldn't find any info on this error.
What should be done to fix?
# Set Admin Security Group Object ID
export aadObjectId=$(az ad group show --group 'cc_ADMINS' --query 'objectId')
# Set Admin Group as SQL AD Admin
az sql server ad-admin create \
--display-name 'cc_ADMINS' \
--object-id $aadObjectId\
--resource-group $resourceGroup \
--server-name $serverName
Check whether the $aadobjectid contains any Double Quotes (") and remove them if present, to see if the issue is persistent.
There is an issue reported and open at https://github.com/Azure/azure-cli/issues/16620
Ended up finding the answer in the official docs here.
To remove the "" around the returned object, use the --output tsv flag.

In postgresql: CREATE ROLE works but createuser doesn't

I'm new to PostgreSQL and was following this tutorial. I can create roles just fine but when I tried to use the createuser and dropuser commands, it just doesn't do anything and no new users are created or any deleted. I tried to use it with and without the semi colon at the end, the former gives a syntax error and the latter just doesn't do anything.
postgres-# createuser joe;
ERROR: syntax error at or near "createuser"
LINE 1: createuser
^
postgres=# ;
postgres=# createuser joe;
ERROR: syntax error at or near "createuser"
LINE 1: createuser joe;
^
postgres=# createuser joe
postgres-# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
admin | Superuser, Create DB | {}
john | Superuser, Create role, Create DB, Replication | {}
guest | | {}
guest3 | | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
I also tried this:
createuser --interactive joe
This also didn't do anything.
What's the correct way to use createuser? I'm using the following version.
postgres (PostgreSQL) 11.1
Inside the psql tool you need to enter SQL commands. To create a user from SQL, you need to use create user.
The tutorial probably was running the command line utility createuser (not the SQL command)
To understand why:
postgres=# createuser joe
did not do anything, see: In psql, why do some commands have no effect?
I think you need a space between your command, something like the following:
CREATE USER youruser WITH ENCRYPTED PASSWORD 'yourpass';
GRANT ALL PRIVILEGES ON DATABASE yourdbname TO youruser;
Command createuser need to run in console(bash). No need to do it in psql.
Example:
createuser -h localhost -p 5432 joe

LDAP query to get account name from SID

So I have a SID of a FSP: S-1-5-21-2127521184-1604012920-1887927527-72713.
Translation worked in powershell but I would like to do the ldap query by myself, like here but have a little trouble with proper SID conversion.
Could you help me with query that give me a corresponding account name based on SID ?
You can bind directly to an object using the SID using LDAP://<SID=S-1-5-21-2127521184-1604012920-1887927527-72713>. Then get the username after that.
In PowerShell, it would look something like:
$account = [adsi]"LDAP://<SID=S-1-5-21-2127521184-1604012920-1887927527-72713>"
$username = $account.Properties["sAMAccountName"]
If the computer you run this from is on a different domain than the account, you may have to specify the domain:
$account = [adsi]"LDAP://domain.com/<SID=S-1-5-21-2127521184-1604012920-1887927527-72713>"
If you have Java available you can query the ObjectSID directly.
We show an Example with code
I am able to use an ldapsearch like:
ldapsearch -h example.net -D "EXAMPLE\myID" -b "OU=Accounts,DC=EXAMPLE,DC=NET" -s sub -a search -z 1000 "(ObjectSID=S-1-5-21-333675845-1535931152-1111140340-22234762)" "objectClass"
And get results.
# extended LDIF
# LDAPv3
# base <OU=Accounts,DC=EXAMPLE,DC=NET> with scope subtree
# filter: (ObjectSID=S-1-5-21-333675845-1535931152-1111140340-22234762)
# requesting: objectClass samAccountName
#
# userid, sales, Accounts, EXAMPLE.NET
dn: CN=userid,OU=sales,OU=Accounts,DC=EXAMPLE,DC=NET
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
sAMAccountName: userid
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
This search is done from a Linux machine and done by a user that is not represented by the ObjectSID.

Resources