A web-based dashboard for managing Step CA – the open-source certificate authority. Built with Flask and styled with AdminLTE, it provides an intuitive UI to manage ACME accounts, X.509 and SSH certificates, provisioners, and system services.
Step CA is an open-source, private certificate authority (CA) designed for developers, DevOps, and security teams. It provides secure, automated certificate management for internal infrastructure, including:
- X.509 certificates for TLS/SSL
- SSH certificates for secure access
- ACME protocol support for automation
Step CA is highly configurable, supports multiple provisioner types (JWK, ACME, OIDC, etc.), and is production-ready for modern infrastructure.
Official Documentation:
https://smallstep.com/docs/step-ca
Important:
- Step CA must be configured to use an external database such as PostgreSQL. See the Step CA Database documentation for setup instructions.
- You must also enable the Remote Provisioner in your Step CA configuration to allow this admin UI to manage provisioners and admins remotely.
- ACME Management
- List and manage ACME Accounts, Orders, Certificates, Authorizations, and Challenges.
- X.509 Certificate Management
- View valid and revoked certificates with detailed info and linked provisioners.
- SSH Certificate Management
- View all issued SSH certificates.
- Provisioner Management
- List, add, and delete JWK/ACME provisioners.
- Admin Users
- View and manage admin provisioners.
- Step CA Config Editor
- Edit and validate the
ca.jsonfile with JSON syntax highlighting.
- Edit and validate the
- Systemd Service Control
- Start, stop, or restart the Step CA systemd service (with limited permissions).
- Dashboard Overview
- Visual KPIs: number of active certs, revoked certs, provisioners, etc.
stepca-web/
├── app/
│ ├── blueprint/
│ │ ├── acme/
│ │ │ └── routes.py
│ │ ├── home/
│ │ │ └── routes.py
│ │ ├── step/
│ │ │ └── routes.py
│ │ ├── system/
│ │ │ └── routes.py
│ │ └── x509/
│ │ └── routes.py
│ ├── libs/
│ │ ├── cert_utils.py
│ │ ├── db_acme.py
│ │ ├── db_conn.py
│ │ ├── db_step.py
│ │ ├── db_x509.py
│ │ └── stepapi.py
│ ├── templates/
│ │ └── ... (Jinja2 HTML templates)
│ └── static/
│ └── ... (CSS, JS, icons)
├── requirements.txt
├── README.md
└── jwk_key.json
The backend is organized using Flask blueprints:
- app/blueprint/acme/routes.py: ACME account/order/cert/authz/challenge views
- app/blueprint/x509/routes.py: X.509 certificate management
- app/blueprint/step/routes.py: Provisioner and admin management, Step CA service control
- app/blueprint/system/routes.py: App/system configuration
- app/blueprint/home/routes.py: Dashboard and summary
- db_acme.py: Functions to fetch ACME accounts, orders, certs, authzs, challenges from PostgreSQL.
- db_x509.py: Functions to fetch X.509 certs, revoked certs, and related metadata.
- db_step.py: Functions to fetch provisioners and admins.
- StepCAClient: Main class for interacting with Step CA's REST API.
list_provisioners(),get_provisioner(name),create_provisioner_jwk(),create_provisioner_acme(),update_provisioner(),delete_provisioner()list_admins(),create_admin(),delete_admin()sign(),revoke(): Certificate signing and revocation- Internal helpers for JWT, JWK, and certificate handling
parse_cert(),parse_cert_from_bytes(): Parse and extract details from PEM/DER certificates.decode_certificate(): Extracts subject, issuer, validity, SANs, etc.extract_sans_from_csr(): Extract SANs from a CSR.
/acme/accounts– List ACME accounts/acme/orders– List ACME orders/acme/certs– List ACME certificates/acme/authzs– List ACME authorizations/acme/challenges– List ACME challenges
/x509/all– List all X.509 certificates/x509/active– List active X.509 certificates/x509/revoked– List revoked X.509 certificates/x509/download/<serial>– Download a certificate/x509/sign(POST) – Sign a new certificate (CSR)/x509/revoke(POST) – Revoke a certificate
/step/provisioners– List/add provisioners (GET/POST)/step/provisioner/<name>/delete– Delete a provisioner/step/admins– List/add admins (GET/POST)/step/admin/<id>/delete– Delete an admin/step/service– Service control UI/step/service/<action>(POST) – Start/stop/restart/status for Step CA systemd service
/system/config– Edit application/database/CA config
/– Dashboard overview
The GUI is built with Flask/Jinja2 templates and styled using AdminLTE and Bootstrap.
- Dashboard: Shows KPIs for certificates, provisioners, and revoked certs.
- ACME Management: Tables for accounts, orders, certs, authorizations, and challenges.
- X.509 Management: Tables for all, active, and revoked certificates. Modal dialogs for certificate details and actions (sign, revoke, download).
- Provisioner Management: Table of provisioners with add/edit/delete modals.
- Admin Management: Table of admin users with add/edit/delete modals.
- Config Editor: JSON editor for
ca.jsonwith validation. - Service Control: Buttons to start/stop/restart Step CA via systemd.
- Navigation: Sidebar for quick access to all sections.
- Python 3.9+
- Linux with
systemd(for service management) - Step CA installed and configured
- PostgreSQL database with Step CA data
- A configured admin provisioner (JWK)
-
Clone the repository
git clone https://github.com/damhau/stepca-web cd stepca-web -
Create a virtual environment
python3 -m venv venv source venv/bin/activate -
Install dependencies
pip install -r requirements.txt
-
Generate the
jwk_key.jsonfileThis file is required for admin JWT authentication with Step CA.
Run the following command (replace"Admin JWK"with your provisioner name if different):step ca provisioner list \ | jq -r '.[] | select(.name == "Admin JWK") | .encryptedKey' \ | step crypto jwe decrypt \ | jq > jwk_key.json
-
Configure the database and CA connection
- Edit
app/settings.jsonor use the/system/configpage in the GUI. - Set your PostgreSQL host, user, password, database, and port.
- Set your Step CA URL and fingerprint.
- Edit
-
Run the app
flask run
Then open your browser at: http://localhost:5000
-
The app expects a PostgreSQL database with Step CA tables (
x509_certs,acme_accounts,provisioners, etc.). -
Connection parameters are set in
settings.jsonor via the/system/configpage. -
Example config:
{ "database": { "host": "localhost", "user": "step-ca", "password": "step-ca", "name": "step_ca_db", "port": 5432 }, "ca": { "url": "https://ca.example.com", "fingerprint": "YOUR_CA_FINGERPRINT" } }
- Use the built-in Flask dev server for local testing.
- For UI, modify
app/templates/andapp/static/. - To add new pages, extend
layout.htmland register routes in the appropriate blueprint. - Backend logic is in
app/libs/and blueprints inapp/blueprint/.
- Add user authentication (basic auth or OAuth)
- Implement audit logging
- Add filtering and searching in tables
- Support bulk certificate operations
- UI for creating short-lived MTLS certs
Damien Hauser
[email protected]
References: