Restricting use of signing keys
User story
A Debusine instance should be able to hold signing keys for use by a small number of trusted users. No other (non-sysadmin) user on the Debusine instance should be able to make Debusine take any action with these keys.
Requirements
Access to signing keys is controlled by
debusine:signing-key
assets. Assets are a new primitive similar to an artifact, but containing only JSON data.Access can be granted to tasks in a set of Workspaces.
Access can be restricted to a Group of users.
Security Model
Key Creation:
Sysadmins can generate HSM-keys, outside Debusine.
Sysadmins can import HSM keys into Debusine.
Sysadmins can generate keys in Debusine.
In the future, we expect key generation (of some sort, but it may as well be HSM) to be a routine part of creating a workspace that holds a repository. Probably delegated by a workflow, once #634 has landed.
Assets:
While artifacts may be created by any user with contributor access to a workspace, assets can only be created by administrators or certain tasks (e.g. key generation).
Assets have a category (like artifacts).
Asset data is immutable (like artifacts).
Unlike artifacts, which have permissions applied by the containing workspace, Assets have permissions directly associated with them, that can be altered by their owner.
Asset’s permissions may be tied to workspaces. Roles are defined on an (asset, workspace) pair. There may be optional extra JSON restrictions attached to a permission for defence-in-depth.
Signing Key Assets:
Signing key assets are used to manage the security of signing keys. They contain the fingerprint, purpose, and public part of the key.
The
GenerateKey
task will create a signing key asset.The
GenerateKey
task can be directly executed by scope owners.The
GenerateKey
task may be incorporated in workflows.In the future, the execution of the
GenerateKey
task may be unrestricted.The extra restrictions field in a signing key asset can include restrictions for any/all of:
debian:repository
,debian:suite
, anddebian:source-package
.Assets may be visible in the UI. If they aren’t, then the public part of the key still needs to be exposed. We expect repositories to have UI with instructions for configuring
sources.list
including the public key. This would be sufficient, no dedicated asset view is required.
Signing:
Debusine’s signing service has no concept of permissions, itself. Currently, if a user can generate a
Sign
task, it will be acted on, with the specified private key (by public key fingerprint, as a string).The
Sign
task may be incorporated into workflows. The workflow creator can then specify the signing key to be used.Sign
tasks should be permitted to execute if the user running the task has theSIGNER
role on the asset (via a group membership) in the workspace that the task is executing in. If any other defence-in-depth restrictions are set, they must be met.Sign
tasks should not be dispatched unless the user is permitted to use the given signing key.The signing service can make API requests back to the Debusine server to make permission determinations, as a final check.
In the future, once we have more comprehensive permissions for workflows, we may grant permission to execute a
Sign
task if the workflow was created and blessed by a user who has permission to use a given signing key. See #634.
Automated Signing:
When we have APT repositories implemented, it will be necessary for
Sign
tasks to be triggered periodically, by Debusine, without any user linked to the request.These Signing Key Assets for these repositories will have a permission granting the
SIGNER
role to the workspace hosting the repository, without any associated group.
Work Requests:
It’s expected that core work request properties are immutable once the work request has been created. At least:
workspace
,created_by
,created_at
,task_type
,task_name
, andtask_data
.
Implementation
Stage 1: Implement Assets
Create the
Asset
DB model, with the following fields:id
int: unique ID (autogenerated)category
string: an ontology, e.g.debusine:signing-key
.workspace
string: owning workspace.created_at
timestamp: creation date.data
: JSON data.
Create the
debusine:signing-key
Asset Pydantic model, modelling the followingdata
:purpose
string ENUM containing:uefi
, oropenpgp
.fingerprint
string containing the fingerprint for the key, calculated using the standard hash algorithm for the type of key.public_key
string containing the public part of the key.description
optional string description.
Put a constraint on assets that ensures all
debusine:signing-key
assets are unique by fingerprint.Create the
AssetRole
DB model with the following fields:resource
Foreign Key toAsset
.role
string ENUM containing:OWNER
.group
Foreign Key toGroup
.
Create the
AssetUsage
DB model with the following fields:asset
Foreign Key toAsset
.workspace
Foreign Key toWorkspace
.restrictions
JSON. Optional additional defense-in-depth restrictions.
Create the
AssetUsageRole
DB model with the following fields:resource
Foreign Key toAssetUsage
.role
string ENUM containing:SIGNER
.group
Foreign Key toGroup
.
Implement
AssetQuerySet
with the following permission filters:can_manage_permissions
, checks if the user has access to theOWNER
role.
Implement
AssetUsageQuerySet
with the following permission filters:can_sign_with
, checks if the user has the ability to sign with this key in the given workspace.
Stage 2: Migrate to Signing Key Assets
Remove the
debian:suite-signing-keys
collection, it’s no longer needed.Create
debusine:signing-key
assets in theGenerateKey
task.Update documentation for manual key creation.
Migrate
debusine:signing-key
artifacts to createdebusine:signing-key
assets. Create a group for each asset, granting the creatorOWNER
rights. Create anAssetUsage
row for each asset, granting the OWNER group theSIGNER
role in the workspace that used to own the artifact.Remove
debusine:signing-key
artifacts.
Stage 3: Permissions for Signing Tasks
We implement an API for a worker to query whether it has the required permission:
1.0/asset/<str:asset_category>/<str:asset_slug>/<str:permission-name>/
ex:1.0/asset/debusine:signing-key/uefi:FBE...64/can-sign/
Input Data:
artifact_id
: int (debusine:signing-input
)work_request_id
: intworkspace_id
: int
Response Data:
has_permission
: booleanusername
: (optional) string (for the audit log)resource
: (optional) JSON description of the resource being signed (e.g.repository
,suite
,package
) (for the audit log)
We modify the
Sign
task to call this API.Store identifying data (
username
andresource
) indata
in theAuditLog
model.
Future Utilization
We define data in the
task-configuration
collection to instruct workflows to use specific keys for each task.