hsed — Hash | Sign | Encrypt | Decrypt
A Unix chmod-inspired permission model for cryptographic operations. If
chmod taught rwx, hsed teaches who can touch cryptographic operations
and how.
hsed 15 → HSED → full authority (root)
hsed 12 → HS-- → sign only (CI/CD)
hsed 3 → --ED → vault (secrets manager)
hsed 9 → H--D → audit (forensics)
since 2012
The Model
Four permission bits on a 4-bit mask:
| Bit | Value | Operation |
|---|---|---|
| H | 8 | Hash / Verify — compute hashes, verify signatures |
| S | 4 | Sign — create digital signatures, attestations |
| E | 2 | Encrypt — seal data, create ciphertext |
| D | 1 | Decrypt — unseal data, read plaintext |
Combine them like octal: hsed 12 = H(8) + S(4) = hash and sign only.
Built-in Roles
| Role | Value | Label | Description |
|---|---|---|---|
root |
15 | HSED | Full authority |
admin |
14 | HSE- | H+S+E, no decrypt |
signer |
12 | HS-- | CI/CD pipelines, code signing |
vault |
3 | --ED | Secrets management |
audit |
9 | H--D | Compliance, forensics, read-only |
encryptor |
10 | H-E- | Data ingestion, DMZ encryptors |
verifier |
8 | H--- | Signature verification only |
none |
0 | ---- | No permissions — deny all |
Install
pip install hsed # core (zero deps)
pip install hsed[aws] # + boto3 (AWS KMS)
pip install hsed[vault] # + hvac (HashiCorp Vault)
pip install hsed[azure] # + azure-mgmt-keyvault, azure-identity
pip install hsed[gcp] # + google-cloud-kms
pip install "hsed[aws,vault]" # multiple integrations
pip install "hsed[all]" # everything
Python API
Basic usage
from hsed import Policy, Role, Bit, enforce
policy = Policy('ci-prod')
policy.add_role(Role('signer', permissions=12)) # H+S
@policy.enforce_op(role='signer', requires=Bit.SIGN)
def sign_artifact(data: bytes) -> bytes:
return sign_data(data) # ✓ allowed
@policy.enforce_op(role='signer', requires=Bit.DECRYPT)
def decrypt_secret(ct: bytes) -> bytes:
return decrypt_data(ct) # ✗ raises HSEDPermissionError immediately
Standalone decorator
from hsed import Role, Bit, enforce
signer = Role('signer', permissions=12)
@enforce(role=signer, requires=Bit.SIGN)
def sign(data: bytes) -> bytes:
...
Built-in roles
from hsed import Policy, builtin_role
p = Policy('production')
p.add_builtin('signer') # adds Role('signer', permissions=12)
p.add_builtin('vault') # adds Role('vault', permissions=3)
Policy serialisation
p = Policy('production', description='Prod crypto policy')
p.add_builtin('signer')
p.add_builtin('audit')
p.save('production.hsed') # writes JSON
p2 = Policy.load('production.hsed') # roundtrip
Permission helpers
from hsed import permission_string, parse_permission_string, combine, intersect
permission_string(12) # 'HS--'
parse_permission_string('H-E-') # 10
combine(8, 4) # 12 (union)
intersect(15, 12) # 12 (intersection)
Temporary scope (tests / auditing)
from hsed import Role, Bit, PermissionScope
r = Role('signer', permissions=12)
with PermissionScope(r, add=Bit.DECRYPT):
r.can(Bit.DECRYPT) # True — temporarily elevated
r.can(Bit.DECRYPT) # False — restored
CLI
# List all built-in roles
hsed role list
# Inspect a role
hsed role show signer
# Create a policy file
hsed policy init --name ci-prod --roles signer audit --output ci-prod.hsed
# Validate a policy for anomalies
hsed policy validate ci-prod.hsed
# Audit a policy file (static)
hsed audit ci-prod.hsed
# Generate AWS KMS IAM policy
hsed generate aws-kms \
--policy ci-prod.hsed \
--role signer \
--key-arn arn:aws:kms:us-east-1:123456789012:key/mrk-abc123
# Generate HashiCorp Vault HCL policy
hsed generate vault \
--policy ci-prod.hsed \
--role signer \
--mount transit \
--key ci-signing-key
# Generate Azure Key Vault access policy
hsed generate azure \
--policy ci-prod.hsed \
--role signer \
--tenant-id 00000000-0000-0000-0000-000000000000 \
--object-id aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
# Generate Azure RBAC role assignment
hsed generate azure-rbac \
--policy ci-prod.hsed \
--role signer \
--scope /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{vault} \
--principal-id aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
# Generate GCP Cloud KMS IAM binding
hsed generate gcp-kms \
--policy ci-prod.hsed \
--role signer \
--member serviceAccount:ci-runner@project.iam.gserviceaccount.com \
--resource projects/my-project/locations/global/keyRings/prod/cryptoKeys/signing-key
# Generate GCP binding as gcloud command
hsed generate gcp-kms ... --gcloud
# Live audit: fetch actual AWS KMS key policy and diff against HSED definition
hsed live-audit aws-kms \
--policy ci-prod.hsed \
--role signer \
--key-arn arn:aws:kms:us-east-1:123456789012:key/mrk-abc123 \
--profile production
AWS KMS Integration
from hsed import Policy, Role
from hsed.integrations.aws_kms import AWSKMSGenerator
policy = Policy('ci')
policy.add_role(Role('signer', permissions=12))
gen = AWSKMSGenerator(policy)
doc = gen.generate(
role='signer',
key_arn='arn:aws:kms:us-east-1:123456789012:key/mrk-abc',
principal='arn:aws:iam::123456789012:role/ci-runner',
)
print(doc.to_json())
HSED → KMS action mapping:
| Bit | KMS Actions |
|---|---|
| H | kms:Verify, kms:GetPublicKey, kms:DescribeKey |
| S | kms:Sign, kms:GetPublicKey, kms:DescribeKey |
| E | kms:Encrypt, kms:GenerateDataKey, kms:GenerateDataKeyWithoutPlaintext, kms:DescribeKey |
| D | kms:Decrypt, kms:GenerateDataKey, kms:DescribeKey |
Destructive operations (kms:DeleteAlias, kms:ScheduleKeyDeletion, etc.) are
always denied via an explicit Deny statement regardless of role.
HashiCorp Vault Integration
from hsed.integrations.vault import VaultGenerator
gen = VaultGenerator(policy)
doc = gen.generate(role='signer', mount='transit', key_name='ci-signing-key')
print(doc.to_hcl())
Azure Key Vault Integration
from hsed.integrations.azure_keyvault import AzureKeyVaultGenerator
gen = AzureKeyVaultGenerator(policy)
# Access policy (classic vault model)
doc = gen.generate(
role='signer',
tenant_id='00000000-0000-0000-0000-000000000000',
object_id='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
)
print(doc.to_json())
# RBAC role assignment
rbac = gen.generate_rbac(
role='signer',
scope='/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{vault}',
principal_id='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
)
print(rbac.to_json())
HSED → Azure key permissions mapping:
| Bit | Azure Key Permissions |
|---|---|
| H | verify, get |
| S | sign, get |
| E | encrypt, wrapKey, get |
| D | decrypt, unwrapKey, get |
HSED → Azure RBAC built-in role:
| HSED mask | Azure Role |
|---|---|
| H+S+E+D | Key Vault Crypto Officer |
| H+S, E+D, others | Key Vault Crypto User |
| H only | Key Vault Reader |
GCP Cloud KMS Integration
from hsed.integrations.gcp_kms import GCPKMSGenerator
gen = GCPKMSGenerator(policy)
doc = gen.generate(
role='signer',
member='serviceAccount:ci-runner@project.iam.gserviceaccount.com',
resource='projects/my-project/locations/global/keyRings/prod/cryptoKeys/signing-key',
)
print(doc.to_json())
# As a gcloud command
print(doc.to_gcloud_command())
HSED → GCP predefined role mapping:
| HSED mask | GCP Role |
|---|---|
| HS-- (12) | roles/cloudkms.signerVerifier |
| --ED ( 3) | roles/cloudkms.cryptoKeyEncrypterDecrypter |
| H--D ( 9) | roles/cloudkms.cryptoKeyDecrypter |
| H-E- (10) | roles/cloudkms.cryptoKeyEncrypter |
| H--- ( 8) | roles/cloudkms.viewer |
| HSED (15) | roles/cloudkms.cryptoKeyEncrypterDecrypter |
Live Audit (AWS KMS)
Fetch the actual key policy from AWS and diff it against your HSED definition.
from hsed.integrations.live_audit import AWSLiveAuditor
policy = Policy.load('production.hsed')
auditor = AWSLiveAuditor(policy, aws_profile='production')
result = auditor.audit(
role='signer',
key_arn='arn:aws:kms:us-east-1:123456789012:key/mrk-abc',
)
print(result.summary())
# Live Audit — Role 'signer' (hsed:HS--/12)
# Key: arn:aws:kms:...
# ✓ [OK] Policy matches HSED definition exactly
# Result: PASS
Use strict=True to treat over-grants as FAIL instead of WARN.
Requires pip install hsed[aws].
Templates
Drop-in infrastructure templates for common deployment patterns:
templates/
├── aws-kms/
│ ├── main.tf # KMS key + per-role IAM policies + key policy
│ ├── variables.tf # principal ARNs per HSED role, key spec, tags
│ └── outputs.tf # key ARN, policy ARNs, hsed audit command
├── hashicorp-vault/
│ └── policy.hcl # Transit policy template (replace {{KEY_NAME}})
└── kubernetes/
└── rbac.yaml # ClusterRole + ServiceAccount per HSED role
# with Workload Identity / IRSA annotation stubs
Repo Layout
hsed/
├── hsed/
│ ├── core/
│ │ ├── permissions.py # Bit model, Role, helpers
│ │ ├── policy.py # Policy — role registry + serialisation
│ │ └── enforcement.py # @enforce, PolicyEnforcer, PermissionScope
│ ├── integrations/
│ │ ├── aws_kms.py # AWS KMS IAM policy generation
│ │ ├── vault.py # HashiCorp Vault HCL generation
│ │ ├── azure_keyvault.py # Azure Key Vault access policy + RBAC
│ │ ├── gcp_kms.py # GCP Cloud KMS IAM bindings
│ │ └── live_audit.py # Live audit via boto3 (AWS KMS)
│ └── cli/
│ └── main.py # CLI entry point
├── tests/
│ ├── test_hsed.py # Core + AWS + Vault tests
│ └── test_integrations_v2.py # Azure + GCP + live audit tests
├── templates/
│ ├── aws-kms/ # Terraform
│ ├── hashicorp-vault/ # HCL
│ └── kubernetes/ # RBAC YAML
└── examples/
├── cicd-pipeline/ # signer role (HS--/12)
├── secrets-manager/ # vault + encryptor + audit roles
├── audit-trail/ # audit role + multi-cloud report
└── zero-trust/ # all roles, all cloud providers
Development
git clone https://github.com/ruwgxo/hsed
cd hsed
pip install -e ".[dev]"
pytest tests/ -v
See SPECIFICATION.md for the full design rationale and CHANGELOG.md for version history.
License
MIT
Metadata
Release files for hsed 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hsed-0.3.1.tar.gz | 65.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hsed-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 110.8 kB
Release files / hsed-0.3.1.tar.gz
| Download URL | hsed-0.3.1.tar.gz |
|---|---|
| Size | 65.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0f7baf7472accae0b01cbcbe4be4e67eef60033f6f25b61e55aacdad7c64dfc8
|
|
BLAKE2b-256 checksum How to use checksums |
a4654820ed81888133a85fb841d35e01d52d658857322ee41a8a8cce2a54fb61
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.0
|
Release files / hsed-0.3.1-py3-none-any.whl
| Download URL | hsed-0.3.1-py3-none-any.whl |
|---|---|
| Size | 45.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
56f3f68c51f47a9af06a6fac8acbb9b6e3b1745428b381e7be97d02763807159
|
|
BLAKE2b-256 checksum How to use checksums |
60fbc22f50a6504494ca7685f4c298ba92e4bc0da2cf83de7d441d6b2ee0f757
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.0
|