generated from coulomb/repo-seed
258 lines
6.0 KiB
Markdown
258 lines
6.0 KiB
Markdown
---
|
|
id: ops-warden.ssh-certificate.sign
|
|
name: Ops-Warden SSH certificate signing
|
|
namespace: ops-warden:ssh-certificate
|
|
version: v1
|
|
status: ready
|
|
package: flexauth.ops_warden.ssh_signing
|
|
actions:
|
|
- sign
|
|
owner: team:platform-security
|
|
fixtures:
|
|
- policy_fixtures.yaml
|
|
caring:
|
|
profile: caring-0.4.0-rc2
|
|
enforce: false
|
|
canonical_roles:
|
|
- Operator
|
|
organization_relations:
|
|
- ServiceProvider
|
|
scopes:
|
|
- level: Platform
|
|
id: platform:ssh-signing
|
|
tenant: tenant:platform
|
|
planes:
|
|
- Identity
|
|
- Secret
|
|
- Audit
|
|
capabilities:
|
|
- Use
|
|
- Operate
|
|
- Audit
|
|
exposure_modes:
|
|
- Metadata
|
|
conditions:
|
|
- TimeLimited
|
|
- Logged
|
|
restrictions:
|
|
- PrivilegeEscalationBlocked
|
|
- SecretAccessBlocked
|
|
activation:
|
|
mode: local
|
|
metadata:
|
|
source: examples/ops-warden/policy_package.md
|
|
ops_warden_policy_gate: v2
|
|
---
|
|
|
|
# Ops-Warden SSH Certificate Signing
|
|
|
|
This package authorizes ops-warden's opt-in pre-sign policy gate. The caller
|
|
keeps SSH CA custody, actor inventory, and OpenBao signing; flex-auth decides
|
|
whether a specific `sign` request is allowed now.
|
|
|
|
## Rules
|
|
|
|
```rego
|
|
import future.keywords.contains
|
|
import future.keywords.if
|
|
import future.keywords.in
|
|
|
|
actor_types := {"adm", "agt", "atm"}
|
|
|
|
decision := {"effect": "allow", "reason": "signing_policy_matched"} if {
|
|
allowed
|
|
} else := {"effect": "deny", "reason": first_denial} if {
|
|
true
|
|
}
|
|
|
|
allowed if {
|
|
input.action == "sign"
|
|
input.resource.system == "ops-warden"
|
|
input.resource.type == "ssh-certificate"
|
|
effective_tenant == "tenant:platform"
|
|
valid_actor_type
|
|
subject_type_matches_context
|
|
actor_type_matches_resource
|
|
resource_id_matches_actor
|
|
subject_id_allowed
|
|
valid_ttl
|
|
has_pubkey_fingerprint
|
|
principals_allowed
|
|
}
|
|
|
|
default effective_tenant := ""
|
|
|
|
effective_tenant := input.tenant if {
|
|
is_string(input.tenant)
|
|
input.tenant != ""
|
|
} else := input.resource.tenant if {
|
|
is_string(input.resource.tenant)
|
|
input.resource.tenant != ""
|
|
} else := input.subject.tenant if {
|
|
is_string(input.subject.tenant)
|
|
input.subject.tenant != ""
|
|
}
|
|
|
|
default first_denial := "no_matching_rule"
|
|
|
|
first_denial := "wrong_action" if {
|
|
input.action != "sign"
|
|
} else := "wrong_system" if {
|
|
input.resource.system != "ops-warden"
|
|
} else := "wrong_resource_type" if {
|
|
input.resource.type != "ssh-certificate"
|
|
} else := "wrong_tenant" if {
|
|
effective_tenant != "tenant:platform"
|
|
} else := "unknown_actor_resource" if {
|
|
not has_actor_resource
|
|
} else := "unknown_subject" if {
|
|
not subject_id_allowed
|
|
} else := "actor_type_mismatch" if {
|
|
not valid_actor_type
|
|
} else := "actor_type_mismatch" if {
|
|
not subject_type_matches_context
|
|
} else := "actor_type_mismatch" if {
|
|
not actor_type_matches_resource
|
|
} else := "actor_resource_mismatch" if {
|
|
not resource_id_matches_actor
|
|
} else := "ttl_out_of_bounds" if {
|
|
not valid_ttl
|
|
} else := "missing_pubkey_fingerprint" if {
|
|
not has_pubkey_fingerprint
|
|
} else := "missing_principal" if {
|
|
not has_principals
|
|
} else := "disallowed_principal" if {
|
|
count(disallowed_principals) > 0
|
|
}
|
|
|
|
has_actor_resource if {
|
|
is_string(input.resource.attributes.actor_id)
|
|
input.resource.attributes.actor_id != ""
|
|
}
|
|
|
|
valid_actor_type if {
|
|
is_string(input.context.actor_type)
|
|
input.context.actor_type in actor_types
|
|
}
|
|
|
|
subject_type_matches_context if {
|
|
input.subject.type == input.context.actor_type
|
|
}
|
|
|
|
subject_type_matches_context if {
|
|
input.subject.attributes.actor_type == input.context.actor_type
|
|
}
|
|
|
|
actor_type_matches_resource if {
|
|
input.context.actor_type == input.resource.attributes.actor_type
|
|
}
|
|
|
|
resource_id_matches_actor if {
|
|
input.resource.id == sprintf("ssh-cert:actor/%s", [input.resource.attributes.actor_id])
|
|
}
|
|
|
|
subject_id_allowed if {
|
|
input.subject.id in input.resource.attributes.allowed_subjects
|
|
}
|
|
|
|
has_ttl if {
|
|
is_number(input.context.ttl_hours)
|
|
}
|
|
|
|
valid_ttl if {
|
|
has_ttl
|
|
input.context.ttl_hours > 0
|
|
input.context.ttl_hours <= input.resource.attributes.max_ttl_hours
|
|
}
|
|
|
|
has_pubkey_fingerprint if {
|
|
is_string(input.context.pubkey_fingerprint)
|
|
input.context.pubkey_fingerprint != ""
|
|
}
|
|
|
|
has_principals if {
|
|
count(input.context.principals) > 0
|
|
}
|
|
|
|
principals_allowed if {
|
|
has_principals
|
|
count(disallowed_principals) == 0
|
|
}
|
|
|
|
allowed_principal(principal) if {
|
|
principal in input.resource.attributes.allowed_principals
|
|
}
|
|
|
|
disallowed_principals contains principal if {
|
|
principal := input.context.principals[_]
|
|
not allowed_principal(principal)
|
|
}
|
|
```
|
|
|
|
## Tests
|
|
|
|
```rego test
|
|
package flexauth.ops_warden.ssh_signing_test
|
|
|
|
import future.keywords.if
|
|
import data.flexauth.ops_warden.ssh_signing
|
|
|
|
adm_request := {
|
|
"id": "check:ops-warden-platform-steward-adm",
|
|
"tenant": "tenant:platform",
|
|
"subject": {"id": "platform-steward", "type": "adm"},
|
|
"action": "sign",
|
|
"resource": {
|
|
"id": "ssh-cert:actor/platform-steward",
|
|
"type": "ssh-certificate",
|
|
"system": "ops-warden",
|
|
"attributes": {
|
|
"actor_id": "platform-steward",
|
|
"actor_type": "adm",
|
|
"allowed_subjects": ["platform-steward", "iam:platform-steward"],
|
|
"allowed_principals": ["platform", "root"],
|
|
"max_ttl_hours": 8
|
|
}
|
|
},
|
|
"context": {
|
|
"actor_type": "adm",
|
|
"principals": ["platform"],
|
|
"pubkey_fingerprint": "SHA256:example-adm-fingerprint",
|
|
"ttl_hours": 4
|
|
}
|
|
}
|
|
|
|
test_adm_sign_allowed if {
|
|
ssh_signing.decision.effect == "allow" with input as adm_request
|
|
}
|
|
|
|
test_high_ttl_denied if {
|
|
ssh_signing.decision.reason == "ttl_out_of_bounds" with input as {
|
|
"tenant": "tenant:platform",
|
|
"subject": {"id": "platform-steward", "type": "adm"},
|
|
"action": "sign",
|
|
"resource": adm_request.resource,
|
|
"context": {
|
|
"actor_type": "adm",
|
|
"principals": ["platform"],
|
|
"pubkey_fingerprint": "SHA256:example-adm-fingerprint",
|
|
"ttl_hours": 12
|
|
}
|
|
}
|
|
}
|
|
|
|
test_missing_fingerprint_denied if {
|
|
ssh_signing.decision.reason == "missing_pubkey_fingerprint" with input as {
|
|
"tenant": "tenant:platform",
|
|
"subject": {"id": "platform-steward", "type": "adm"},
|
|
"action": "sign",
|
|
"resource": adm_request.resource,
|
|
"context": {
|
|
"actor_type": "adm",
|
|
"principals": ["platform"],
|
|
"ttl_hours": 4
|
|
}
|
|
}
|
|
}
|
|
```
|