How do I create a secret to access Azure Blob storage if I am using SAS token authentication mode?
{
"account_name": "<value>",
"container_name": "<value>",
"container_uri": "<value>",
"region": "<value>",
"sas_token": "<value>"
}
I cannot find any information about this on the docs
You create a SAS from the protal or via az cli:
AZURE_RESOURCE_GROUP="my-rg"
AZURE_STORAGE_ACCOUNT="my-sa"
export AZURE_STORAGE_CONNECTION_STRING="$(az storage account show-connection-string \
--name "$AZURE_STORAGE_ACCOUNT" \
--resource-group "$AZURE_RESOURCE_GROUP" \
-o tsv)"
AZURE_STORAGE_SAS_TOKEN="$(az storage account generate-sas \
--services b \
--resource-types co \
--permissions dlpruwac \
--expiry "$(date -d '+7 days' '+%FT%H:%MZ')" \
-o tsv)"
Note the --services, --resource-types and --permissions flags. In the above example the token was generated for blob storage, on container & objects within the container with the permissions: delete, list, process, read, update, write, add & create.
--permissions [Required] : The permissions the SAS grants. Allowed values: (a)dd (c)reate
(d)elete (f)ilter_by_tags (i)set_immutability_policy (l)ist
(p)rocess (r)ead (t)ag (u)pdate (w)rite (x)delete_previous_version
(y)permanent_delete. Can be combined.
--resource-types [Required] : The resource types the SAS is applicable for. Allowed values:
(s)ervice (c)ontainer (o)bject. Can be combined.
--services [Required] : The storage services the SAS is applicable for. Allowed values:
(b)lob (f)ile (q)ueue (t)able. Can be combined.
See more info with az storage account generate-sas --help.
Once you have the token you can create the secret (Note, you need the variables from the previous code snippet).
AZURE_STORAGE_ACCOUNT_CONTAINER="<my-container>"
jq -n \
--arg account_name "$AZURE_STORAGE_ACCOUNT" \
--arg container_name "$AZURE_STORAGE_ACCOUNT_CONTAINER" \
--arg container_uri "$(az storage account show -n "$AZURE_STORAGE_ACCOUNT" -g "$AZURE_RESOURCE_GROUP" --query primaryEndpoints.blob -o tsv)$AZURE_STORAGE_ACCOUNT_CONTAINER" \
--arg region "$(az storage account show -n "$AZURE_STORAGE_ACCOUNT" -g "$AZURE_RESOURCE_GROUP" --query primaryLocation -o tsv)" \
--arg sas_token "$AZURE_STORAGE_SAS_TOKEN" '{
"account_name": $account_name,
"container_name": $container_name,
"container_uri": $container_uri,
"region": $region,
"sas_token": $sas_token
}' |
kubectl create secret generic storage-account --from-file=data.json=/dev/stdin
You can change the name of the secret and the file name within the secret by modifying the kubectl command.
You also need to check if you should append the container name to the container uri yourself or if the library using this data is doing it. Above, I have added the container name, you may want to remove it from the uri.
If you dont need to append the container name to the uri, you could simplify the json generation like this below. Using a query to get multiple fields from az cli.
AZURE_STORAGE_ACCOUNT_CONTAINER="<my-container>"
az storage account show -n $AZURE_STORAGE_ACCOUNT -g $AZURE_RESOURCE_GROUP \
--query '{account_name:name,container_uri:primaryEndpoints.blob,region:primaryLocation}' |
jq --arg sas_token "$AZURE_STORAGE_SAS_TOKEN" --arg container_name "$AZURE_STORAGE_ACCOUNT_CONTAINER" \
'. + { "sas_token": $sas_token, "container_name": $container_name}' |
kubectl create secret generic storage-account --from-file=data.json=/dev/stdin
Related
In my release pipeline I'm using a Azure CLI to transfer my build files to a Azure storage blob:
call az storage blob upload-batch --source "$(System.DefaultWorkingDirectory)/_ClientWeb-Build-CI/ShellArtifact/out/build" --destination "$web" --account-key "****QxjclDGftOY/agnqUDzwNe/gOIAzsQ==" --account-name "*****estx"
This works, but I want to retrieve the account-key dynamically.
When I use:
az storage account keys list -g CustomersV2 -n ****estx
I get a array with 2 objects, both holding a key value:
[
{
"keyName": "key1",
"permissions": "Full",
"value": "f/eybpcl*****************Vm9uT1PwFC1D82QxjclDGftOY/agnqUDzwNe/gOIAzsQ=="
},
{
"keyName": "key2",
"permissions": "Full",
"value": "bNM**********L6OxAemK1U2oudW5WGRQW++/bzD6jVw=="
}
]
How do I use one of the two keys in my upload-batch command?
For your issue, if you just want one of the two keys for example, the first one. You can set a variable with the key as the value like this:
key=$(az storage account keys list -g CustomersV2 -n ****estx --query [0].value -o tsv)
And then use the variable key in the other command like this:
call az storage blob upload-batch --source "$(System.DefaultWorkingDirectory)/_ClientWeb-Build-CI/ShellArtifact/out/build" --destination "$web" --account-key $key --account-name "*****estx"
Or you can just put the command which gets the key in the other command directly like this:
call az storage blob upload-batch --source "$(System.DefaultWorkingDirectory)/_ClientWeb-Build-CI/ShellArtifact/out/build" --destination "$web" --account-key $(az storage account keys list -g CustomersV2 -n ****estx --query [0].value -o tsv) --account-name "*****estx"
Update
According to what you said, it seems you run the command in the windows command prompt, it's different from the Linux shell and PowerShell. You cannot set the environment variable with the value that the output of a command. You can do that like this:
az storage account keys list -g CustomersV2 -n ****estx --query [0].value -o tsv > key.txt
set /P key=<key.txt
az storage blob upload-batch --source "$(System.DefaultWorkingDirectory)/_ClientWeb-Build-CI/ShellArtifact/out/build" --destination "$web" --account-key %key% --account-name "*****estx"
And it seems you just can quote the environment variable as %variable_name%, so it seems it's a wrong way to use "$web" in your command.
I created a Azure Powershell task (version 4) that does:
az login -u **** -p ****
Write-Host "##vso[task.setvariable variable=storageKey;]az storage account keys list -g ***** -n ***** --query [0].value -o tsv"
$key = az storage account keys list -g ***** -n **** --query [0].value -o tsv
Write-Host "##vso[task.setvariable variable=something;]$key"
Then I can use the something variable in my Azure CLI task:
call az storage blob upload-batch --source "$(System.DefaultWorkingDirectory)/_ClientWeb-Build-CI/ShellArtifact/out/build" --destination "$web" --account-key $(something) --account-name "*****"
And this works. You'll probably need to put the -u and -p in a variable though.
#Charles thanks a lot for this line (az storage account keys list -g **** -n ****estx --query [0].value -o tsv) !
I'm using Microsoft Azure CLI and I could not find a way to list the blob object of a storage account.
I have the list displayed in Azure Web portal but I don't find any away to do it with the az storage command.
I've tried az storage blob list but it required a container name which I don't know how to find it (with az cli).
Do someone have an idea ?
Update: fetch the account key in cli:
Please try the code below, which can list all the blobs in all the containers of your storage account.
Note that there are no whitespaces aroud "=".
# list storage account names
az storage account list --query "[].{name:name}" --output tsv)"
# update with your storage account name
storage_account_name="your_storage_account_name"
key="$(az storage account keys list -n ${storage_account_name} --query "[0].{value:value}" --output tsv)"
containers="$(az storage container list --account-name ${storage_account_name} --account-key $key --query "[].{name:name}" --output tsv)"
for c in $containers
do
echo "==== Blobs in Container $c ===="
az storage blob list --container-name $c \
--account-name ${storage_account_name} \
--account-key $key \
--query "[].{name:name}" --output tsv
done
Test results as below:
Command to get list of containers in a storage account on basis of storage ACCOUNT_NAME and ACCESS_KEY:
az storage container list --account-key ACCESS_KEY --account-name ACCOUNT_NAME
On basis of Container names received in its response, you can use az storage blob list command to get the list of objects within that container.
Thanks Ivan Yang for your answer!
The suggested edits queue was full for your answer, so I wanted to paste back this edited code:
get_blobs.sh
accounts="$(az storage account list --query "[].{name:name}" --output tsv)"
for storage_account_name in $accounts
do
echo "==== Storage Account ${storage_account_name} ===="
key="$(az storage account keys list -n ${storage_account_name} --query "[0].{value:value}" --output tsv)"
containers="$(az storage container list --account-name ${storage_account_name} --account-key $key --query "[].{name:name}" --output tsv)"
for c in $containers
do
echo "==== Blobs in Container $c ===="
az storage blob list --container-name $c \
--account-name ${storage_account_name} \
--account-key $key \
--query "[].{name:name}" --output tsv
done
done
I ran mine in Azure Cloud CLI:
Launch Cloud Shell from the top navigation of the Azure portal. Choose Bash.
Save the script with Unix line endings. Drag the file onto the Azure CLI to upload it. If you get an error with ^r line endings, run dos2unix get_blobs.sh on the file to fix that.
chmod u+x get_blobs.sh to allow it to execute.
./get_blobs.sh >> output.txt to run and output to text file.
You can then use the Azure CLI Upload/Download Button to retrieve your output.txt file.
If I understand correctly, the solution can be divided in 3 part
Get the list of storage accounts and copy the "desired" account name from output
az storage account list --query "[].{name:name}" --output tsv
Then get "first key" of "desired" account and copy the string (dont copy double quotes :) )
az storage account keys list --account-name WHATEVER_ACCOUNTNAME --query "[0].value"
3- Finally get the list of containers of your desired account (catch is here that "key" should be correctly copied from the output of second command)
az storage container list --account-name WHATEVER_ACCOUNTNAME --account-key YOUR-VERY-VERY-LONG-KEY --query "[].{name:name}" --output tsv
Note- Don't forget to login into azure account first of all :).
az login
Here is a simple script to list all your blob containers. As a bonus, list all your file shares too !
# List all the storage accounts under a subscription
for actname in $( az storage account list --query "[].name" --output tsv );
do
# Get the storage key
key1=`az storage account keys list --account-name $actname --query "[0].value" --output tsv 2>/dev/zero`
# Exclude the listing when you do not have permission to look into the storage account - like databricks managed storage for example
if [ $? -ne 0 ] ; then
continue
fi
echo -e "\n === Here are the storage containers for your storage account $actname === \n"
# List of containers and file shares for the account
az storage container list --account-name $actname --account-key $key1 --query "[].name" --output tsv
echo -e "\n --- Here are the storage file shares for your storage account $actname ---\n"
az storage share list --account-name $actname --account-key $key1 --query "[].name" --output tsv
done
I'm wondering how can I retrieve scale set VM's private IP address with Terraform-provider-azurerm. I think there are no resources nor data resources directly return VM IP's.
One option I tried was generate shellscript via template resource.
# get_vmss_privateip.tpl
#!/bin/bash
cap=`az vmss show \
--resource-group ${resource_group} \
--subscription ${subscription} \
--name ${name} \
--query 'sku.capacity'`
for i in `seq 1 $cap`
do
az resource show \
--resource-group ${resource_group} \
--resource-type Microsoft.Compute/virtualMachineScaleSets \
--api-version 2017-03-30 \
--name ${name}/virtualMachines/$i/networkInterfaces \
--query 'value[0].properties.ipConfigurations[0].properties' \
| jq -c '{privateIPAddress}'
done
then run terraform to generate sh.
data "template_file" "private_ip_scripts" {
template = "${file("templates/get_vmss_privateip.tpl")}"
vars {
resource_group = "${data.azurerm_resource_group.current.name}"
subscription = "${data.azurerm_subscription.current.subscription_id}"
name = "${azurerm_virtual_machine_scale_set.test.name}"
}
}
resource "local_file" "test_private_ip_scripts" {
filename = "scripts/get_vmss_instance_private_ip.sh"
content = "${data.template_file.manage_private_ip_scripts.rendered}"
}
But this approach is too far from goal, and I do want to use private IP's in the terraform, not outside terraform.
Do anyone have much better ideas?
EDIT 2018/11/2
I've done via external data resource.
data "external" "vmss_test_private_ip" {
program = ["bash", "${local_file.test_private_ip_scripts.filename}"]
}
output hoge {
value = "${data.external.vmss_test_private_ip.result}"
}
This type of resource can be imported into TF Scale Set. So this is one option, only hassle is there are a lot of attributes and importing introduces other issues. I've found one or two things that aren't exposed as data resources in the AzureRM provider. Might be worth adding a request to the GitHub repo?
Regards,
Is there a way to find out given instrumentation key belongs to which subscription?
First go to Azure Cloud Shell. It gives you bash and allows you to access all your azure resources.
Second create a file findApplicationByIkey.sh with the following content:
!/bin/bash
if [ -z "$ikeyToFind" ]; then
echo "specify the instrumentaiton key"
exit
fi
echo "search for instrumentation key $1"
ikeyToFind=$1
# this function search for the instrumentation key in a given subscription
function findIKeyInSubscription {
echo "Switch to subscription $1"
az account set --subscription $1
# list all the Application Insights resources.
# for each of them take an instrumentation key
# and compare with one you looking for
az resource list \
--namespace microsoft.insights --resource-type components --query [*].[id] --out tsv \
| while \
read ID; \
do printf "$ID " && \
az resource show --id "$ID" --query properties.InstrumentationKey --o tsv; \
done \
| grep "$ikeyToFind"
}
# run the search in every subscription...
az account list --query [*].[id] --out tsv \
| while read OUT; do findIKeyInSubscription $OUT; done
Finally, run it: ./findApplicationByIkey.sh provide key here
e.g. ./findApplicationByIkey.sh e645a06e-d500-402e-ad4a-0bdcc4062dab
Test#Azure:~/Test$ ./findApplicationByIkey.sh e645a06e-d500-402e-ad4a-0bdcc4062dab
search for instrumentation key e645a06e-d500-402e-ad4a-0bdcc4062dab
A few accounts are skipped as they don't have 'Enabled' state. Use '--all' to display them.
Switch to subscription
Switch to subscription
...
...
Final output will be like -
/subscriptions/<subscriptionid>/resourceGroups/MY-RG/providers/microsoft.insights/components/test-ai-app
I'm starting to write a bash script to provision a VM in a new or existing resource group so that we can enforce naming convention and configuration.
In a bash script how can I check that a resource already exists so I don't try to create it again?
# 1. If a new resource group is desired, create it now. Microsoft Docs
az group create --name $RESOURCEGROUPNAME --location $LOCATION
# 2. Create a virtual network and subnet if one has not already been created. Microsoft Docs
# Consider a separate VNet for each resource group.
# az network vnet list -output table
az network vnet create \
--resource-group $RESOURCEGROUPNAME \
--name $RESOURCEGROUPNAME-vnet \
--address-prefix 10.0.x.0/24 \
--subnet-name default \
--subnet-prefix 10.0.x.0/24
# x is the next available 3rd octet value
# 3. Create a public IP Address. Microsoft Docs
az network public-ip create \
--resource-group $RESOURCEGROUPNAME \
--name $VMNAME-ip \
--dns-name $DNSNAME
# 4. Create a network security group. Microsoft Docs
az network nsg create \
--resource-group $RESOURCEGROUPNAME \
--name $VMNAME-nsg
# 5. Create a rule to allow SSH to the machine. Microsoft Docs
az network nsg rule create \
--resource-group $RESOURCEGROUPNAME \
--nsg-name $VMNAME-nsg \
--name allow-ssh \
--protocol tcp \
--priority 1000 \
--destination-port-range 22 \
--access allow
# 6. Create a virtual NIC. Microsoft Docs
az network nic create \
--resource-group $RESOURCEGROUPNAME \
--name $VMNAME-nic \
--vnet-name $RESOURCEGROUPNAME-vnet \
--subnet default \
--public-ip-address $VMNAME-ip \
--network-security-group $VMNAME-nsg
# 7. Create an availability set, if redundancy is required. Microsoft Docs
az vm availability-set create \
--resource-group $RESOURCEGROUPNAME \
--name $AVSETNAME-as
# 8. Create the VM. Microsoft Docs
az vm create \
--resource-group $RESOURCEGROUPNAME \
--location $LOCATION \
--name $VMNAME \
--image UbuntuLTS \
--size $VMSIZE \
--availability-set $AVSETNAME-as \
--nics $VMNAME-nic \
--admin-username $ADMINUSERNAME \
--authentication-type ssh
--ssh-key-value #$SSHPUBLICKEYFILE \
--os-disk-name $VMNAME-osdisk
This should work in bash script:
if [ $(az group exists --name $RESOURCEGROUPNAME) = false ]; then
az group create --name $RESOURCEGROUPNAME --location $LOCATION
fi
In a bash script how can I check that a resource already exists so I
don't try to create it again?
We can use CLI 2.0 command az group exists to test the resource group exist or not, like this:
C:\Users\user>az group exists -n jasontest
false
In this way, before we create it, we can test the name available or not. In new resource group, we can create new Vnet and other resources.
For now, there is no CLI 2.0 command to test other resource exist or not. If you want to create resource in an existing resource group, maybe we should use CLI 2.0 command to list the resources, and use bash to make sure the resource exist or not.
You can use JMESPath queries to do this. All resource types support this, AFAIK.
For example, for VMs:
az vm list --resource-group $RESOURCEGROUPNAME --query "[?name=='$VMNAME'] | length(#)"
This will output the number of matching VMs - either 1 or 0.
You can use this to create if/else logic in bash as follows.
if [[ $(az vm list --resource-group $RESOURCEGROUPNAME --query "[?name=='$VMNAME'] | length(#)") > 0 ]]
then
echo "VM exists"
else
echo "VM doesn't exist"
fi
If a resource show command returns an empty string and a success status code (0), then the resource does not exist.
Edit: ChrisWue pointed out that this is no longer true. It must have changed since I left the Azure CLI team (it used to be a requirement that all commands worked like this). Or it may be that there is a bug for the key vault commands he mentioned below.
this work for my batch commands
call az webapp show --subscription <yoursubs> --resource-group <yourrg> --name <yourappname> -query name
if %errorlevel% == 1 (
az webapp create ...
)
As mentioned in another answer - there is no generic "exists" command. One line of reasoning I've found was that "create" is meant to be idem potent - therefor if you have a script that creates resources (for example as part of a build pipeline) it doesn't matter how often you execute it since "it will do the right thing".
If you still need to do this you can do it in shell like this (the example is for keyvault but it should work for all resource types that have a show command)
if az keyvault show -n my-keyvault -o none; then
echo "keyvault exists"
else
echo "keyvault doesn't exist"
fi
It should be noted that az will output an error message to stderr if the resource doesn't exists - this doesn't affect the check but if it bothers you then you can redirect stderr to /dev/null
In our case we needed this because we don't run the infra scripts if the setup hasn't changed (cuts our build time in half). We dectect this by creating a hash of the infra-scripts and store it in a keyvault. When the script runs it creates the keyvault (to make sure it exists) and then tries to check the secret that contains the hash. If the hash is still the same then don't run the rest of the script.
Catch is that keyvault create nukes the access policies which also includes the web-app managed identity access policy which won't get added if the rest of the script doesn't run ... so the fix is to check if the keyvault exists first and to not create it if it does.