Files
seaweedfs/weed/iam/policy/trust_policy_implicit_deny_test.go
T
Chris LuandDevin 62d4f9152a iam: evaluate trust policies deny-by-default (#11513)
* iam: evaluate trust policies deny-by-default

EvaluateTrustPolicy seeded its result with the engine's DefaultEffect,
so a non-matching trust-policy statement set still resolved to Allow
when the IAM config sets policy.defaultEffect=Allow. A caller holding
a validly signed token from a registered provider could then assume a
role its trust policy does not admit.

Trust policies now start from implicit deny, matching AWS semantics and
the pre-d751623 behavior of evaluateTrustPolicy; DefaultEffect still
governs identity-policy evaluation.

Upgrade note: deployments on defaultEffect=Allow whose trust policies do
not match their callers will see those assumptions refused.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* iam: cover trust policy implicit deny under DefaultEffect=Allow

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-29 11:36:01 +08:00

81 lines
3.1 KiB
Go

package policy
import (
"context"
"encoding/json"
"testing"
)
const subjectBoundTrustPolicy = `{"Version":"2012-10-17","Statement":[{"Effect":"Allow",
"Principal":{"Federated":"https://oidc.example"},"Action":["sts:AssumeRoleWithWebIdentity"],
"Condition":{"StringEquals":{"oidc:sub":"spiffe://example.org/ns/app/sa/app"}}}]}`
func webIdentityContext(sub string) *EvaluationContext {
return &EvaluationContext{
Principal: "web-identity-user",
Action: "sts:AssumeRoleWithWebIdentity",
Resource: "arn:aws:iam::role/app",
RequestContext: map[string]interface{}{
"aws:FederatedProvider": "https://oidc.example",
"oidc:iss": "https://oidc.example",
"oidc:sub": sub,
},
}
}
// A trust policy is deny-by-default. The engine's DefaultEffect decides
// requests no identity policy speaks to; it must not let a principal the trust
// policy does not allow assume the role.
func TestEvaluateTrustPolicyIsImplicitDenyWhateverTheDefaultEffect(t *testing.T) {
var trust PolicyDocument
if err := json.Unmarshal([]byte(subjectBoundTrustPolicy), &trust); err != nil {
t.Fatalf("parse test trust policy: %v", err)
}
for _, defaultEffect := range []string{"Allow", "Deny"} {
t.Run("defaultEffect="+defaultEffect, func(t *testing.T) {
engine := NewPolicyEngine()
if err := engine.Initialize(&PolicyEngineConfig{DefaultEffect: defaultEffect, StoreType: "memory"}); err != nil {
t.Fatalf("initialize policy engine: %v", err)
}
res, err := engine.EvaluateTrustPolicy(context.Background(), &trust, webIdentityContext("spiffe://example.org/ns/other/sa/x"))
if err != nil {
t.Fatalf("evaluate trust policy: %v", err)
}
if res.Effect != EffectDeny {
t.Errorf("a subject the trust policy does not allow got %s", res.Effect)
}
res, err = engine.EvaluateTrustPolicy(context.Background(), &trust, webIdentityContext("spiffe://example.org/ns/app/sa/app"))
if err != nil {
t.Fatalf("evaluate trust policy: %v", err)
}
if res.Effect != EffectAllow {
t.Errorf("the subject the trust policy allows got %s", res.Effect)
}
})
}
}
func TestEvaluateTrustPolicyExplicitDenyWins(t *testing.T) {
var trust PolicyDocument
doc := `{"Version":"2012-10-17","Statement":[
{"Effect":"Allow","Principal":{"Federated":"https://oidc.example"},"Action":["sts:AssumeRoleWithWebIdentity"]},
{"Effect":"Deny","Principal":{"Federated":"https://oidc.example"},"Action":["sts:AssumeRoleWithWebIdentity"],
"Condition":{"StringEquals":{"oidc:sub":"spiffe://example.org/ns/app/sa/app"}}}]}`
if err := json.Unmarshal([]byte(doc), &trust); err != nil {
t.Fatalf("parse test trust policy: %v", err)
}
engine := NewPolicyEngine()
if err := engine.Initialize(&PolicyEngineConfig{DefaultEffect: "Allow", StoreType: "memory"}); err != nil {
t.Fatalf("initialize policy engine: %v", err)
}
res, err := engine.EvaluateTrustPolicy(context.Background(), &trust, webIdentityContext("spiffe://example.org/ns/app/sa/app"))
if err != nil {
t.Fatalf("evaluate trust policy: %v", err)
}
if res.Effect != EffectDeny {
t.Errorf("explicit Deny did not win: %s", res.Effect)
}
}