Skip to main content

AWX/AAP credential plugin for Delinea (Thycotic) Secret Server

Project description

Delinea Secret Server — AWX/AAP Credential Plugin

CI Release PyPI version PyPI - Python Version Coverage License Code style: black Imports: isort

Custom AWX/AAP managed credential plugin for Delinea (Thycotic) Secret Server. Authenticates via OAuth2 at job launch, retrieves a short-lived token, and injects it into the runtime — the raw password is never exposed to the running job.


Architecture

┌──────────────────────┐
│   AAP / AWX          │
│                      │
│  ┌────────────────┐  │       POST /oauth2/token
│  │ Credential     │──│──────────────────────────────┐
│  │ Plugin         │  │                              │
│  │ (Python)       │◄─│──────────────────────────────┤
│  └───────┬────────┘  │      { "access_token": ... } │
│          │           │                              │
│          ▼           │                    ┌─────────┴──────────┐
│  ┌────────────────┐  │                    │ Delinea Secret     │
│  │ Injector       │  │                    │ Server             │
│  │ (env + extras) │  │                    │ (OAuth2 endpoint)  │
│  └───────┬────────┘  │                    └────────────────────┘
│          │           │
│          ▼           │
│  ┌────────────────┐  │
│  │ Ansible Job    │  │
│  │ (playbook)     │  │
│  │                │  │
│  │ TSS_TOKEN ✔    │  │
│  │ PASSWORD  ✘    │  │
│  └────────────────┘  │
└──────────────────────┘

Table of Contents


Quick Start

Install

pip install awx-delinea-secret-server-credential-plugin

Then on every AWX/AAP node:

awx-manage setup_managed_credential_types

Do I need the credential_type/ YAML files?

No. This package uses the AWX managed credential plugin pattern:

  • It exposes a CredentialPlugin object through Python entry points
  • Input schema is defined in Python (inputs)
  • AWX discovers it via awx-manage setup_managed_credential_types

The credential_type/ YAML files are kept as reference only.


Development

Prerequisites

  • Python 3.8+
  • GNU Make
  • Git

Setup

git clone https://github.com/acedya/tss-credential-plugin.git
cd tss-credential-plugin
make install-dev      # creates .venv, installs package + dev deps

Makefile Reference

The Makefile is the single source of truth — CI workflows call make targets, so local and CI behavior stay perfectly aligned.

Target Description
make help Show all available targets
make install-dev Install package with dev dependencies in .venv
make format Auto-format code (black + isort)
make lint CI-equivalent lint checks (black, isort, flake8, mypy)
make test Run unit tests
make test-ci CI-equivalent tests with coverage XML
make build Build source + wheel distributions
make release-check Build + twine check
make ci Full CI-equivalent run: lint + test-ci + build
make release-tag TAG=v0.2.1 [PUSH=1] Safe validated release tag creation
make clean Remove caches, bytecode, build artifacts

Project Structure

.
├── credential_plugins/
│   ├── __init__.py
│   └── delinea_secret_server.py       # Main plugin module
├── tests/
│   ├── __init__.py
│   └── test_delinea_credential_plugin.py
├── credential_type/                   # Reference YAML (not used at runtime)
├── examples/
│   └── example_playbook.yaml
├── scripts/
│   └── release.sh                     # Safe tag helper
├── .github/workflows/
│   ├── ci.yml                         # Test / lint / build
│   └── release.yml                    # PyPI publish / GitHub Release
├── pyproject.toml                     # Package metadata + tool config
├── Makefile                           # Single source of truth for CI
├── CHANGELOG.md                       # Release notes
└── README.md

Plugin Details

Credential Input Fields

Field Type Required Secret Description
server_url string Yes No Base URL (e.g. https://myserver/SecretServer)
username string Yes No Application user name
password string Yes Yes Password (encrypted at rest by AAP)
domain string No No Application user domain

Injector Output

The plugin injects only the OAuth2 token and server URL — never the raw password.

Type Variable Value
Environment TSS_SERVER_URL Secret Server URL
Environment TSS_TOKEN OAuth2 access token
Extra var tss_server_url Secret Server URL
Extra var tss_token OAuth2 access token

Implementation

  • _get_access_token(server_url, username, password, domain, verify_ssl) POSTs to {server_url}/oauth2/token with grant_type=password. Returns the access_token string. Raises requests.HTTPError on failure, KeyError if token missing.

  • backend(credential_params) AWX entry point called at job launch. Calls _get_access_token(), returns {"tss_token": ..., "tss_server_url": ...}.

OAuth2 Token Flow

POST {server_url}/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=password&username={username}&password={password}&domain={domain}
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 1200
}

Testing

Run Tests

make ci               # full CI parity: lint + test + build
make test             # unit tests only
make test-ci          # tests with coverage XML
make test-verbose     # verbose output
make lint             # lint checks only

Test Matrix

Test Description
test_get_access_token_success Token returned on successful OAuth2 call
test_get_access_token_without_domain Domain is optional, absent from request
test_get_access_token_http_error HTTPError raised on non-2xx
test_get_access_token_missing_key KeyError raised when access_token missing
test_backend_returns_token_and_url backend() returns expected dict
test_backend_password_not_in_output Raw password never in plugin output

Dependencies

pytest, pytest-cov, responses (HTTP mocking), black, isort, flake8, mypy — all installed via make install-dev.


CI/CD Pipeline

Design Principles

  • Makefile = source of truth: workflows call make targets, never duplicate shell commands
  • Local reproducibility: make cici.yml, make release-checkrelease.yml build step
  • OIDC Trusted Publishing: no API token secrets stored in GitHub

Workflows

Workflow Trigger Jobs
ci.yml Push to main, pull requests Test (matrix: 3.10, 3.11), Lint, Build
release.yml Tag v*.*.* PyPI publish + GitHub Release

Trusted Publishing Setup

This repository uses PyPI OIDC Trusted Publishing — no API token secrets required.

Create a trusted publisher configuration on pypi.org:

Setting Value
Owner Your GitHub org/user
Repository tss-credential-plugin
Workflow release.yml
Environment pypi

Publish trigger: strict vX.Y.Z tags, only if the tagged commit is on main.

Release notes are populated from CHANGELOG.md.

Local Publish Fallback

Token-based publishing is available for emergencies:

make publish-pypi-token PYPI_API_TOKEN=pypi-...

Release Process

Branching Model — GitHub Flow

This project follows GitHub Flow, the simplest branching model:

  1. main is always deployable
  2. Create a branch from main with a descriptive name (e.g. add-ssl-toggle, fix-token-parsing)
  3. Commit your changes and push early for visibility
  4. Open a pull request to start discussion and trigger CI
  5. Review & approve — CI must pass, at least one approval required
  6. Merge to main — branch is deleted after merge
  7. Tag & release when ready: make release-tag TAG=vX.Y.Z PUSH=1

Creating a Release

# 1. Update CHANGELOG.md with the new version notes
# 2. Create and validate the tag
make release-tag TAG=v0.2.1

# 3. Push when ready (triggers PyPI publish + GitHub Release)
make release-tag TAG=v0.2.1 PUSH=1

Safety Checks (scripts/release.sh)

The release helper enforces:

  • Strict vX.Y.Z semver format
  • Must be on main branch
  • Clean git working tree
  • Tag must not exist locally or on origin
  • make ci must pass before tag creation

Server-side guard: release.yml verifies the tagged commit is an ancestor of origin/main.


Deployment to AAP/AWX

  1. Install the plugin on AWX/AAP nodes (or build a custom Execution Environment)

    pip install awx-delinea-secret-server-credential-plugin
    
  2. Register credential types

    awx-manage setup_managed_credential_types
    
  3. Create a Credential using the Delinea Secret Server type — fill in server_url, username, password, and optionally domain

  4. Attach to a Job Template — the token is injected at launch time as env vars and extra vars


Usage in Playbooks

Via extra vars (recommended)

- name: Retrieve a secret from Delinea Secret Server
  ansible.builtin.debug:
    msg: >-
      {{ lookup('delinea.ss.tss', 42,
                server_url=tss_server_url,
                token=tss_token) }}

Via environment variables

- name: Use environment variables
  ansible.builtin.debug:
    msg: >-
      Server: {{ lookup('env', 'TSS_SERVER_URL') }}
      Token:  {{ lookup('env', 'TSS_TOKEN') }}

Repository Hardening

Apply these in GitHub UI: Settings → Rules → Rulesets.

Branch Protection

main:

  • Require pull request with at least 1 approval
  • Dismiss stale approvals on new commits
  • Require status checks: CI jobs from ci.yml
  • Require conversation resolution
  • Block force pushes and branch deletion

Tag Protection

v*.*.* tags:

  • Restrict creation/update/deletion to maintainers only
  • Works with local guard (scripts/release.sh) and workflow guard (release.yml)

Environment Protection

Environment Configuration
pypi Required reviewers (recommended), limit to protected branches/tags

Contributing

Workflow

  1. Create a branch from main with a descriptive name
  2. Make changes, run make format before committing
  3. Push and open a pull request — CI runs automatically
  4. Get review, iterate, then merge to main

Roadmap

  • Client credentials grant (SDK-based auth)
  • Configurable verify_ssl toggle in credential input
  • Token caching for rapid successive lookups
  • Custom Execution Environment image with plugin pre-installed
  • Integration tests against a real Secret Server instance

License

Apache-2.0

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

Built Distribution

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

File details

Details for the file awx_delinea_secret_server_credential_plugin-0.2.0.tar.gz.

File metadata

File hashes

Hashes for awx_delinea_secret_server_credential_plugin-0.2.0.tar.gz
Algorithm Hash digest
SHA256 ad3ee6a7921e863ee29f0bd6e6388eda81e30402681e3161b4c165ec34571784
MD5 143b353d3f59774789c9d99b46fa18ba
BLAKE2b-256 b6cf4eb0bc8bbc8116d21cfac3b6ae14cee536665ae2080ad8678a859711598c

See more details on using hashes here.

Provenance

The following attestation bundles were made for awx_delinea_secret_server_credential_plugin-0.2.0.tar.gz:

Publisher: release.yml on acedya/tss-credential-plugin

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

File details

Details for the file awx_delinea_secret_server_credential_plugin-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for awx_delinea_secret_server_credential_plugin-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e74bf4c5ac44d6a59d4c7e769871cd818e87df9da895fb3f0b6e0d6f56b0d063
MD5 6b7fb9ab2bbf422713a02befcf5bd163
BLAKE2b-256 da68e56a3b24e5679a1288b495d92b54e6438c9c6c8cf18fbf101ecbd0fc714f

See more details on using hashes here.

Provenance

The following attestation bundles were made for awx_delinea_secret_server_credential_plugin-0.2.0-py3-none-any.whl:

Publisher: release.yml on acedya/tss-credential-plugin

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