Instantly share code, notes, and snippets.

Embed
What would you like to do?
MintyOffline - Offline Minting of Shared Access Signatures (SAS) URLs & Tokens for Azure Storage Accounts (e.g. Blob Storage) - Alpha v0.0.3
import os
from argparse import ArgumentParser
import logging
import sys
#import os
import json
import base64
import hmac
import hashlib
import urllib
from datetime import datetime, timedelta
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
__author__ = '@TweekFawkes'
__website__ = 'Stage2Sec.com'
__blog__ = 'https://Stage2Sec.com/blog/'
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
'''
--- MintyOffline - Offline Minting of Shared Access Signatures (SAS) URLs & Tokens for Azure Storage Accounts (e.g. Blob Storage) - Alpha v0.0.3 ---
Offline Minting of Shared Access Signatures (SAS) URLs & Tokens for Azure Storage Accounts (e.g. Blob Storage).
Useful for persisting access to an Azure Storage Account once the primary or secondary key have been collected.
What is a shared access signature (SAS)?
To Quote Microsoft:
- "A shared access signature (SAS) provides you with a way to grant limited access to objects in your storage account to other clients, without exposing your account key."
- "A shared access signature provides delegated access to resources in your storage account. With a SAS, you can grant clients access to resources in your storage account, without sharing your account keys. This is the key point of using shared access signatures in your applications--a SAS is a secure way to share your storage resources without compromising your account keys."
See references for more detials.
--- Example Usage ---
... look at the help ...
$ mintyOffline-v0_0_3.py -h
... create an SAS URL/Token for the Storage Account named "bcod030" with the container named "container030"
$ mintyOffline-v0_0_3.py bcod030 container030 rl 1 "HdBVPwDkMQTdgYnQhOnw38jAcRTjJAnnsVtXdfucVr6P89ysjgqq2VuwtmyA4Oeme/jF/WXv1yncNhXGINNWOA=="
...
CRITICAL:root:[+] MintyOffline - Alpha v0.0.3
CRITICAL:root:[+] SAS URL: https://bcod030.blob.core.windows.net/container030?sig=RW7EarpHliaORD21iQkTHp1XeOQFHse47IDqiIRY4yk%3D&srt=co&ss=b&spr=https&sp=rwdalcup&sv=2016-05-31&se=2018-05-10T20%3A46%3A50Z&st=2018-05-10T19%3A41%3A50Z
CRITICAL:root:[+] SAS Token: sig=RW7EarpHliaORD21iQkTHp1XeOQFHse47IDqiIRY4yk%3D&srt=co&ss=b&spr=https&sp=rwdalcup&sv=2016-05-31&se=2018-05-10T20%3A46%3A50Z&st=2018-05-10T19%3A41%3A50Z
...
... browse to blob (e.g. blob030.txt) that is protected using the SAS Token ...
https://bcod030.blob.core.windows.net/container030/blob030.txt?sig=RW7EarpHliaORD21iQkTHp1XeOQFHse47IDqiIRY4yk%3D&srt=co&ss=b&spr=https&sp=rwdalcup&sv=2016-05-31&se=2018-05-10T20%3A46%3A50Z&st=2018-05-10T19%3A41%3A50Z
--- Permissions ---
The following values can be used for permissions:
"a" (Add), "r" (Read), "w" (Write), "d" (Delete), "l" (List)
Concatenate multiple permissions, such as "rwa" = Read, Write, Add
Permissions for Storage:
"rl" = Read, List -> default
"rwa" = Read, Write, Add -> common
"rwdalcup" = Read, Write, Delete, Add, List, Create, Update, Process -> all
--- Setup on Ubuntu 14.04 x64 ---
apt-get update
apt-get -y install python
...
$ python
Python 2.7.6 (default, Oct 26 2016, 20:30:19)
...
>>> exit()
--- References ---
- Using shared access signatures (SAS)
-- https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1
-- https://docs.microsoft.com/en-us/azure/storage/blobs/storage-dotnet-shared-access-signature-part-2
- How do you generate the signature for an Azure Blob storage SAS token in Python?
-- https://stackoverflow.com/questions/41285755/how-do-you-generate-the-signature-for-an-azure-blob-storage-sas-token-in-python?rq=1
- An HTTP trigger Azure Function that returns a SAS token for Azure Storage for the specified container and blob name.
-- https://github.com/yokawasa/azure-functions-python-samples/blob/master/blob-sas-token-generator/function/run.py
- Generate SAS token
-- https://docs.microsoft.com/en-us/rest/api/eventhub/generate-sas-token
'''
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# Automatically Defined Variables
sScriptName = os.path.basename(__file__)
sAppName = 'MintyOffline'
sVersion = 'Alpha v0.0.3'
sAzureStorageApiVersion = '2016-05-31'
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# Get the Arguments
parser = ArgumentParser(add_help=True)
parser.add_argument('storage_account',
action="store",
help="[required] storage account to create SAS token for e.g.: bcod030")
parser.add_argument('container_name',
action="store",
help="[required] container to create SAS token for e.g.: container030")
parser.add_argument('permission',
action="store",
help="[required] permission to set for SAS token e.g.: rl")
parser.add_argument('token_ttl',
action="store",
help="[required] ttl to set for SAS token e.g.: 1")
parser.add_argument('storage_key',
action="store",
help="[required] storage key to use to create SAS token e.g.: HdB...WOA==")
args = parser.parse_args()
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# storage_account = "bcod030"
sStorageAccountName = str(args.storage_account).strip()
logging.critical("[-] sStorageAccountName: " + sStorageAccountName)
#container_name = "container030"
sContainerName = str(args.container_name).strip()
logging.critical("[-] sContainerName: " + sContainerName)
#permission = "rwa" # d l
sPermission = str(args.permission).strip()
logging.critical("[-] sPermission: " + sPermission)
#token_ttl = int(1)
sTokenTtl = str(args.token_ttl).strip()
logging.critical("[-] sTokenTtl: " + sTokenTtl)
iTokenTtl = int(sTokenTtl)
logging.critical("[-] iTokenTtl: " + str(iTokenTtl))
# storage_key = "HdBVPwDkMQTdgYnQhOnw38jAcRTjJAnnsVtXdfucVr6P89ysjgqq2VuwtmyA4Oeme/jF/WXv1yncNhXGINNWOA=="
sStorageKey = str(args.storage_key).strip()
logging.critical("[-] sStorageKey: " + sStorageKey)
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
logging.critical("""
__ ____ __ ____ ___________
/ |/ (_)___ / /___ __/ __ \/ __/ __/ (_)___ ___
/ /|_/ / / __ \/ __/ / / / / / / /_/ /_/ / / __ \/ _ \
/ / / / / / / / /_/ /_/ / /_/ / __/ __/ / / / / / __/
/_/ /_/_/_/ /_/\__/\__, /\____/_/ /_/ /_/_/_/ /_/\___/
/____/
""")
logging.critical("[+] " + sAppName + " - " + sVersion)
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
def generate_sas_token (storage_account, storage_key, permission, token_ttl, container_name, blob_name = None ):
sp = permission
# Set start time to five minutes ago to avoid clock skew.
st= str((datetime.utcnow() - timedelta(minutes=5) ).strftime("%Y-%m-%dT%H:%M:%SZ"))
se= str((datetime.utcnow() + timedelta(hours=token_ttl)).strftime("%Y-%m-%dT%H:%M:%SZ"))
srt = 'o' if blob_name else 'co'
# Construct input value
inputvalue = "{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n".format(
storage_account, # 0. account name
sp, # 1. signed permission (sp)
'b', # 2. signed service (ss)
srt, # 3. signed resource type (srt)
st, # 4. signed start time (st)
se, # 5. signed expire time (se)
'', # 6. signed ip
'https', # 7. signed protocol
sAzureStorageApiVersion) # 8. signed version
# Create base64 encoded signature
hash =hmac.new(base64.b64decode(storage_key),inputvalue,hashlib.sha256).digest()
sig = base64.b64encode(hash)
querystring = {
'sv': sAzureStorageApiVersion,
'ss': 'b',
'srt': srt,
'sp': sp,
'se': se,
'st': st,
'spr': 'https',
'sig': sig,
}
sastoken = urllib.urlencode(querystring)
sas_url = None
if blob_name:
sas_url = "https://{0}.blob.core.windows.net/{1}/{2}?{3}".format(
storage_account,
container_name,
blob_name,
sastoken)
else:
sas_url = "https://{0}.blob.core.windows.net/{1}?{2}".format(
storage_account,
container_name,
sastoken)
return {
'token': sastoken,
'url' : sas_url
}
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
theGoodStuff = generate_sas_token (sStorageAccountName, sStorageKey, sPermission, iTokenTtl, sContainerName, blob_name = None )
logging.critical("[+] SAS URL: " + theGoodStuff['url'] )
logging.critical("[+] SAS Token: " + theGoodStuff['token'] )
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment