Skip to content

Commit

Permalink
Add Azure CLI credentials support
Browse files Browse the repository at this point in the history
  • Loading branch information
lrakai committed Nov 19, 2023
1 parent 56da562 commit ce35c76
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 3 deletions.
8 changes: 8 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
"dependsOn": [
"docker-build"
],
"dockerRun": {
"volumes": [
{
"localPath": "${userHome}/.azure",
"containerPath": "/home/appuser/.azure"
}
],
},
"python": {
"file": "src/entry.py"
}
Expand Down
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ RUN apt-get install debian-archive-keyring && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Install Azure CLI for Azure CLI Credentials
ARG AZ_CLI_VERSION=2.53.1
ARG AZ_DIST=bookworm
RUN mkdir -p /etc/apt/keyrings && \
curl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | tee /etc/apt/keyrings/microsoft.gpg > /dev/null && \
chmod go+r /etc/apt/keyrings/microsoft.gpg && \
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_DIST main" | tee /etc/apt/sources.list.d/azure-cli.list && \
apt-get update --allow-insecure-repositories && \
apt-get install --allow-unauthenticated -y azure-cli=$AZ_CLI_VERSION-1~$AZ_DIST && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Install dev dependencies
RUN python -m pip install --upgrade python-dotenv==1.0.0

Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,35 @@ Environment for working with Azure VCFs

1. Test your check functions are working after trimming and create a pull request on bitbucket labs-vcf-boilerplates with the new `requirements.txt`

## Authentication options

The launch.json encoding of client ID and client secret for authentication works well for debugging the current file.
To streamline the authentication process when debugging using containers (VS Code Docker debug profile), Azure CLI credentials and .config.env files are used.
<ins>.config.env is higher precedence</ins> and Azure CLI credentials are used as a fallback.

### Azure CLI credentials

The Azure CLI credentials are used by the Azure SDK for Python to authenticate with Azure.
The Azure CLI authenticated user (`az login`) and default subscription (`az account set --subscription ...`) are used by the Azure SDK for Python.
The default resource group must also be configured (`az config set defaults.group=...`), or the resource group (`AZURE_RESOURCE_GROUP`) may be defined in isolation in a .config.env file.

### .config.env file

The .config.env file is similar to the environment variables defined in the launch.json file but is a flat file of variable declarations.
The contents of .config.env resemble:

```sh
AZURE_CLIENT_ID=12345678-1234-1234-1234-123456789012
AZURE_CLIENT_SECRET=AL8)RxYQzCf./dF!y5EN13eqdg3T!qwh
AZURE_TENANT_ID=1234abcd-1234-1234-1234-1234abcd1234
AZURE_SUBSCRIPTION_ID=12345678-1234-1234-1234-123456789012
AZURE_RESOURCE_GROUP=your-resource-group
```

As mentioned, Azure CLI credentials may be used in lieu of `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_TENANT_ID`. Refer to [Azure Identity env vars](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/README.md#environment-variables)
If the resource group in the Azure CLI is not set using `az config set defaults.group=...` the .config.env file must declare `AZURE_RESOURCE_GROUP`.
If .config.env does not declare `AZURE_SUBSCRIPTION_ID` the Azure CLI default subscription is used.

## References

- [Azure SDK for Python](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk) (Unit test code in particular)
36 changes: 34 additions & 2 deletions src/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,49 @@

import time
from config import CONFIG
from vcf import handler
import vcf

class credential_helper:
@staticmethod
def get_credentials(event):
from azure.identity import DefaultAzureCredential
import logging
logger = logging.getLogger('azure.identity')
logger.setLevel(logging.CRITICAL)
subscription_id = CONFIG['environment_params']['subscription_id']
credentials = DefaultAzureCredential(exclude_interactive_browser_credential=True, exclude_shared_token_cache_credential=True, exclude_visual_studio_code_credential=True, exclude_managed_identity_credential=True, exclude_shared_ms_i_credential=True, exclude_azure_arc_credential=True)
return credentials, subscription_id

vcf.get_credentials = credential_helper.get_credentials

def timed_handler(event, context):
start = time.time()
result = handler(event, context)
result = vcf.handler(event, context)
end = time.time()
print(end - start)
return result

def entry():
if not CONFIG['environment_params']['resource_group']:
print('Resource group not found in AZURE_RESOURCE_GROUP environment variable. Attempting to retrieve from az config get defaults.group.')
import subprocess, sys
res = subprocess.run(["az", "config", "get", "defaults.group", "--query", "value", "-o", "tsv"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False)
if res.returncode == 0:
resource_group = res.stdout.decode('utf-8').strip('\n')
print(f"Using resource group {resource_group} from az config get defaults.group")
CONFIG['environment_params']['resource_group'] = resource_group
else:
print('Resource group not found in AZURE_RESOURCE_GROUP environment variable and not set with az config set defaults.group. Attempting to continue...', file=sys.stderr)
if not CONFIG['environment_params']['subscription_id']:
print('Subscription ID not found in AZURE_SUBSCRIPTION_ID environment variable. Attempting to retrieve from az account show.')
import subprocess, sys
res = subprocess.run(["az", "account", "show", "--query", "id", "-o", "tsv"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False)
if res.returncode == 0:
subscription_id = res.stdout.decode('utf-8').strip('\n')
print(f"Using Subscription ID {subscription_id} from az account show")
CONFIG['environment_params']['subscription_id'] = subscription_id
else:
print('Subscription ID not found in AZURE_SUBSCRIPTION_ID environment variable and not set in az account show. Attempting to continue...', file=sys.stderr)
result = timed_handler(CONFIG, None)
print(result)

Expand Down
2 changes: 1 addition & 1 deletion src/vcf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def handler(event, context):
ingress_set = resources[0].configuration.ingress.target_port == 8000
reg_config = resources[0].configuration.registries
return ingress_set and len(reg_config) > 0
except:
except Exception as e:
return False

def get_credentials(event):
Expand Down

0 comments on commit ce35c76

Please sign in to comment.