Skip to main content

Python PKCS-11 based Credentials provider for AWS, Azure and GCP

Project description

Cloud Auth Library using PKCS-11

Python library which supports TPPKCS-11 embedded authenticated credentials for various cloud providers.

The supported set of providers and credential types:

on python pypi: https://pypi.org/project/cloud-auth-pkcs/

This code is not affiliated with or supported by google

Also see


Usage

You need to first embed an RSA key into a PKCS-11 device which is described below but is out of scope of this library

The following using SoftHSM /usr/lib/softhsm/libsofthsm2.so

GCPCredentials

If the GCP RSA key is embedded in token1 a with label keylabel1

from google.cloud import storage
from cloud_auth_pkcs.gcp.gcpcredentials import GCPCredentials

####  pip3 install cloud_auth_pkcs[gcp]
pc = GCPCredentials(
  module='/usr/lib/softhsm/libsofthsm2.so',
  token='token1',
  label='keylabel1',
  pin='123456',

  email="jwt-access-svc-account@$PROJECT_ID.iam.gserviceaccount.com")                    

storage_client = storage.Client(project="$PROJECT_ID", credentials=pc)

buckets = storage_client.list_buckets()
for bkt in buckets:
    print(bkt.name)
AWSCredentials

If the AWS RolesAnywhere RSA key is embedded in token1 a with label keylabel2

import boto3
from cloud_auth_pkcs.aws.awscredentials import AWSCredentials

####  pip3 install cloud_auth_pkcs[aws]
pc = AWSCredentials(
  module='/usr/lib/softhsm/libsofthsm2.so',
  token='token1',
  label='keylabel2',
  pin='123456',

  public_certificate_file="certs/alice-cert.crt",
  region="us-east-2",
  duration_seconds=1000,
  trust_anchor_arn='arn:aws:rolesanywhere:us-east-2:291738886522:trust-anchor/a545a1fc-5d86-4032-8f4c-61cdd6ff92ac',
  session_name="foo", 
  role_arn="arn:aws:iam::291738886522:role/rolesanywhere1",
  profile_arn="arn:aws:rolesanywhere:us-east-2:291738886522:profile/6f4943fb-13d4-4242-89c4-be367595c560")

session = pc.get_session()

s3 = session.resource('s3')
for bucket in s3.buckets.all():
    print(bucket.name)
AWSHMACCredentials

If the AWS HMAC Key is embedded in token1 a with label keylabel3

import boto3
from cloud_auth_pkcs.aws.awshmaccredentials import AWSHMACCredentials

####  pip3 install cloud_auth_pkcs[aws]
pc = AWSHMACCredentials(
  module='/usr/lib/softhsm/libsofthsm2.so',
  token='token1',
  label='keylabel3',
  pin='123456',

  access_key="AWS_ACCESS_KEY_ID",
  region="us-east-2",
  duration_seconds=1000,
  role_session_name="foo",
  assume_role_arn="arn:aws:iam::291738886522:role/gcpsts")

session = pc.get_session()

s3 = session.resource('s3')
for bucket in s3.buckets.all():
    print(bucket.name)
AzureCredentials

If the AWS HMAC Key is embedded in token1 a with label keylabel4

from azure.storage.blob import BlobServiceClient
from cloud_auth_pkcs.azure.azurecredentials import AzureCredentials

####  pip3 install cloud_auth_pkcs[azure]
pc = AzureCredentials(
  module='/usr/lib/softhsm/libsofthsm2.so',
  token='token1',
  label='keylabel4',
  pin='123456',

  tenant_id="45243fbe-b73f-4f7d-8213-a104a99e428e",
  client_id="cffeaee2-5617-4784-8a4b-b647efd676e1",
  certificate_path="certs/azclient.crt")

blob_service_client = BlobServiceClient(
    account_url="https://$STORAGE_ACCOUNT.blob.core.windows.net",
    credential=pc
)
container_client = blob_service_client.get_container_client('container_name')
blob_list = container_client.list_blobs()
for blob in blob_list:
    print(blob.name)

Configuration

Option Description
module Path to PKCS Module: (required; default: ``)
token Name of the PKCS TOKEN: (required; default: ``)
label Label set for the key (required; default: ``)
pin PIN for the token: (optional; default: ``)
GCPCredentials
Option Description
email ServiceAccount email (required; default: ``)
scopes Signed Jwt Scopes (optional default: "https://www.googleapis.com/auth/cloud-platform")
keyid ServiceAccount keyid (optional; default: ``)
expire_in Token expiration in seconds (optional; default: 3600)
AWSCredentials
Option Description
public_certificate_file Path to public x509 (required; default: ``)
region AWS Region (optional default: ``)
duration_seconds Duration in seconds for the token lifetime (optional; default: 3600)
trust_anchor_arn RolesAnywhere Trust anchor ARN (required; default: ``)
role_arn RolesAnywhere RoleArn (required; default: ``)
profile_arn RolesAnywhere Profile Arn (Required; default: ``)
session_name AWS Session Name (optional; default: ``)
AWSHMACCredentials
Option Description
region AWS Region (optional default: ``)
aws_access_key_id AWS_ACCESS_KEY_ID if using HMAC based credentials (required; default: ``)
duration_seconds Duration in seconds for the token lifetime (optional; default: 3600)
get_session_token If using GetSessionToken (optional; default: False)
assume_role_arn AssumeRole ARN (required if AssumeRole set; default: ``)
role_session_name RoleSessionName if AssumeRole set (optional; default: ``)
AzureCredentials
Option Description
tenant_id Azure TentantID (required; default: ``)
client_id Azure Application (client) ID (required; default: ``)
certificate_path x509 certificate to authenticate with (required; default ``)

Setup

This demo uses SoftHSM but you are free to use any other PKCS-11 compliant system

apt-get -y install libsofthsm2-dev opensc

# go to the example/ folder and set the path to the softhsm config:
cd example/
rm -rf /tmp/tokens
mkdir /tmp/tokens

export SOFTHSM2_CONF=`pwd`/softhsm.conf
export MODULE="/usr/lib/softhsm/libsofthsm2.so"

## initialize
pkcs11-tool --module $MODULE --list-mechanisms --slot-index 0
pkcs11-tool --module $MODULE  --slot-index=0 \
   --init-token --label="token1" --so-pin="123456"

pkcs11-tool --module $MODULE  --label="token1" \
   --init-pin --so-pin "123456" --pin mynewpin

## print mechanisms
pkcs11-tool --module $MODULE --list-mechanisms --slot-index 0

## print slot details
pkcs11-tool --module $MODULE --list-token-slots

Using RSA Keys on PKCS

First step is to acquire the private RSA keys for whichever provider you're interested in

Once you have the raw RSA private key in in regular PEM format, you can use pkcs11-tool to load the key.

Each provider has its own way to create the raw RSA key and associate it with a cloud credential. See instructions below for each provider.

Setup - GCP

This is an extension of GCP google-auth-python specifically intended to use service account credentials which are embedded inside a PCKS-11 device.

Setup a new key and download the json

export PROJECT_ID=`gcloud config get-value core/project`
export GCP_SA_EMAIL=jwt-access-svc-account@$PROJECT_ID.iam.gserviceaccount.com

gcloud iam service-accounts create jwt-access-svc-account --display-name "Test Service Account"
gcloud iam service-accounts keys create jwt-access-svc-account.json --iam-account=$GCP_SA_EMAIL

gcloud projects add-iam-policy-binding $PROJECT_ID --member=serviceAccount:$GCP_SA_EMAIL --role=roles/storage.admin

## create a test bucket
export GCP_BUCKET=gs://$PROJECT_ID-test
gcloud storage buckets create gs://$GCP_BUCKET --project=$PROJECT_ID

Extract the key_id, email and the raw RSA key.

cat jwt-access-svc-account.json | jq -r '.private_key' > /tmp/rsakey.pem

## convert the rsa key to DER for importing
openssl rsa -text -in /tmp/rsakey.pem
openssl rsa -in /tmp/rsakey.pem -outform DER -out /tmp/gcp_key.der

Import /tmp/gcp_key.der into the device. Once the key is embedded into the device, you can discard the raw key

export MODULE="/usr/lib/softhsm/libsofthsm2.so"

pkcs11-tool  --module $MODULE --pin mynewpin \
   --write-object /tmp/gcp_key.der --type privkey --id 10 --label keylabel3 --slot-index 0

pkcs11-tool --module $MODULE --list-token-slots
pkcs11-tool --module $MODULE  --list-objects --pin mynewpin

Now test the

cd example/
pip3 install -r requirements-gcp.txt

python3 main_gcp.py --module="$MODULE" \
   --token="token1" --label="keylabel3" --pin="mynewpin" \
   --email="$GCP_SA_EMAIL" \
   --project_id="$GCP_PROJECT" --bucket="$GCP_BUCKET"

How it works:

GCP APIs allows for service account authentication using a Self-signed JWT with scope.

What that means is if you take a private key and generate a valid JWT with in the following format, you can just send it to the service as an auth token, that simple.

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "abcdef1234567890"
}
{
  "iss": "jwt-access-svc-account@$PROJECT_ID.iam.gserviceaccount.com",
  "sub": "jwt-access-svc-account@$PROJECT_ID.iam.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/cloud-platform",
  "iat": 1511900000,
  "exp": 1511903600
}

So since we have the RSA key on the TPM, we can use the ESAPI to make it "sign" data for the JWT.

Setup - AWS

AWS Roles Anywhere allows for client authentication based on digital signature from trusted private keys.

The trusted client RSA or EC key is embedded within a PKCS-11 device and that is used to sign the RolesAnywhere header values.

For a detailed example, see AWS SDK CredentialProvider for RolesAnywhere

The following example assumes you have setup RolesAnwwhere and the client certificate and key are available at awsclient.key and awsclient.crt

When you setup RolesAnywhere, note down the ARN for the TrustAnchorArn, ProfileArn and RoleArn as well as the region. Ideally, the role has AmazonS3ReadOnlyAccess to list buckets.

Then attempt to use the credentials and specify the specific ARN values

export AWS_PEM="/path/to/awsclient.key"
export AWS_CERT="/path/to/awsclient.crt"
export AWS_REGION="us-east-2"
export AWS_TRUST_ANCHOR_ARN="arn:aws:rolesanywhere:us-east-2:redacted:trust-anchor/redacted"
export AWS_ROLE_ARN="arn:aws:iam::redacted:role/cicd-role"
export AWS_PROFILE_ARN="arn:aws:rolesanywhere:us-east-2:redacted:profileredacted"
export AWS_HMAC_REGION="us-east-1"

### convert to der and importy the key
openssl rsa -in $AWS_PEM -outform DER -out /tmp/aws_key.der

pkcs11-tool  --module $MODULE --pin mynewpin \
   --write-object /tmp/aws_key.der --type privkey --id 10 --label keylabel5 --slot-index 0

pip3 install -r requirements-aws.txt

python3 main_aws.py --module="$MODULE" \
   --token="token1" --label="keylabel5" --pin="mynewpin" \
   --public_certificate_file="$AWS_CERT" \
   --region="$AWS_REGION" --trust_anchor_arn="$AWS_TRUST_ANCHOR_ARN" \
   --role_arn="$AWS_ROLE_ARN" \
   --profile_arn="$AWS_PROFILE_ARN"
AWS HMAC

AWS supports HMAC based authentication as well. see the following for a TPM equivalent: AWS Credentials for Hardware Security Modules and TPM based AWS_SECRET_ACCESS_KEY and specifically AWS v4 signed request using Trusted Platform Module

This repo includes an example setup and to use this, you need your AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY and embed the secret into the PKCS device and make it perform the HMAC

### first embed the hmac key with an optional password
export AWS_ACCESS_KEY_ID=recacted
export AWS_SECRET_ACCESS_KEY=redacted

## add the AWS4 prefix to the key per the signing protocol
export secret="AWS4$AWS_SECRET_ACCESS_KEY"
echo -n $secret > hmac.key

pkcs11-tool  --module $MODULE --pin mynewpin \
   --write-object /tmp/hmac.key --type secrkey --private --sensitive \
    --usage-sign --private --id 10 --label keylabel4 --slot-index 0 \
      --mechanism SHA256-HMAC 

pip3 install -r requirements-aws.txt

python3 main_aws_hmac.py --module="$MODULE" \
   --token="token1" --label="keylabel4" --pin="mynewpin" \
   --aws_access_key_id=$AWS_ACCESS_KEY \
   --region="$AWS_HMAC_REGION" \
   --assume_role_arn="$AWS_ROLE_ARN"

Setup - Azure

Azure authentication uses an the basic Microsoft identity platform application authentication certificate credentials where the variation here is that the client rsa key is on PKCS

The following example assumes you have set this up similar to

The following assumes you have configured Azure certificate based autentication and the certificate and key are available locally

export AZURE_CLIENT_ID=cffeaee2-5617-4784-8a4b-redacted
export AZURE_TENANT_ID=45243fbe-b73f-4f7d-8213-redacted
export AZURE_STORAGEACCOUNT=redacted
export AZURE_CONTAINER=redacted
export AZURE_CLIENT_PEM="/path/to/azureclient.key"
export AZURE_CERT="/path/to/azureclient.crt"

## test that you have the cert based auth working
az login --service-principal -u $CLIENT_ID -p $CERTIFICATE_PATH_COMBINED_DER --tenant=$TENANT_ID
az account get-access-token   --scope="api://$CLIENT_ID/.default"

## if the principal has access to a storage container, test that
export STORAGE_ACCOUNT=your-storage-account
export CONTAINER=your-container
export AZURE_TOKEN=$(az account get-access-token --resource https://storage.azure.com/ --query accessToken -o tsv)

curl -s --oauth2-bearer "$AZURE_TOKEN"  -H 'x-ms-version: 2017-11-09'  \
     "https://$STORAGE_ACCOUNT.blob.core.windows.net/$CONTAINER?restype=container&comp=list" | xmllint -  --format

## now you're ready to embed the key and test with the client using the embedded  key

openssl rsa -in $AZURE_CLIENT_PEM -outform DER -out /tmp/azure_key.der
pkcs11-tool  --module $MODULE --pin mynewpin \
   --write-object /tmp/azure_key.der --type privkey --id 10 --label keylabel6 --slot-index 0

pip3 install -r requirements-azure.txt

python3 main_azure.py --module="$MODULE" \
   --token="token1" --label="keylabel6" --pin="mynewpin" \
   --certificate_path="$AZURE_CERT" \
   --tenant_id="$AZURE_TENANT_ID" \
   --client_id="$AZURE_CLIENT_ID" \
   --storageaccount="$AZURE_STORAGEACCOUNT"  --container="$AZURE_CONTAINER"

Local Build

to generate the library from scratch and run local, run

python3 setup.py sdist bdist_wheel

cd example
virtualenv env
source env/bin/activate

pip3 install ../
## depending on the variant provider
# pip3 install -r requirements-gcp.txt 
# pip3 install -r requirements-aws.txt 
# pip3 install -r requirements-azure.txt 


### to deploy/upload
# virtualenv env 
# source env/bin/activate
# python3 -m pip install --upgrade build
# python3 -m pip install --upgrade twine
# python3 -m build
# python3 -m twine upload --repository testpypi dist/*
# python3 -m twine upload  dist/*

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloud_auth_pkcs-0.0.21.tar.gz (24.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloud_auth_pkcs-0.0.21-py3-none-any.whl (23.8 kB view details)

Uploaded Python 3

File details

Details for the file cloud_auth_pkcs-0.0.21.tar.gz.

File metadata

  • Download URL: cloud_auth_pkcs-0.0.21.tar.gz
  • Upload date:
  • Size: 24.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cloud_auth_pkcs-0.0.21.tar.gz
Algorithm Hash digest
SHA256 f91c408452d10dc1059d83e7dfd8a2e09595e2cfbe4d97575a04a87a17e8d344
MD5 760601bd7f632aadc2d25ed084063491
BLAKE2b-256 382fc7b8cbd6485b0b0298eae60594c5179a1a395a5c96e8efc0e1756b24d6dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for cloud_auth_pkcs-0.0.21.tar.gz:

Publisher: release.yml on salrashid123/cloud_auth_pkcs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cloud_auth_pkcs-0.0.21-py3-none-any.whl.

File metadata

File hashes

Hashes for cloud_auth_pkcs-0.0.21-py3-none-any.whl
Algorithm Hash digest
SHA256 f9f4a089fe52e7e74fd95106620360accd2bbc9a4eae60a23b64aac0ce691c4e
MD5 c79fb31e464a89260a9cf711645d6d41
BLAKE2b-256 b0983df3b41682f430ff80cef14050e8f3d7d40a0615a3587f501cbfe6888db9

See more details on using hashes here.

Provenance

The following attestation bundles were made for cloud_auth_pkcs-0.0.21-py3-none-any.whl:

Publisher: release.yml on salrashid123/cloud_auth_pkcs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page