mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-30 11:45:42 +00:00
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>
This commit is contained in:
co-authored by
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent
a901c1a5e2
commit
62d4f9152a
@@ -473,8 +473,11 @@ func (e *PolicyEngine) EvaluateTrustPolicy(ctx context.Context, trustPolicy *Pol
|
||||
return nil, fmt.Errorf("trust policy cannot be nil")
|
||||
}
|
||||
|
||||
// A trust policy is deny-by-default, whatever the engine's DefaultEffect:
|
||||
// a role may be assumed only by a principal a trust statement explicitly
|
||||
// allows.
|
||||
result := &EvaluationResult{
|
||||
Effect: Effect(e.config.DefaultEffect),
|
||||
Effect: EffectDeny,
|
||||
EvaluationDetails: &EvaluationDetails{
|
||||
Principal: evalCtx.Principal,
|
||||
Action: evalCtx.Action,
|
||||
@@ -511,7 +514,7 @@ func (e *PolicyEngine) EvaluateTrustPolicy(ctx context.Context, trustPolicy *Pol
|
||||
// AWS IAM evaluation logic:
|
||||
// 1. If there's an explicit Deny, the result is Deny
|
||||
// 2. If there's an Allow and no Deny, the result is Allow
|
||||
// 3. Otherwise, use the default effect
|
||||
// 3. Otherwise, the implicit deny stands
|
||||
if explicitDeny {
|
||||
result.Effect = EffectDeny
|
||||
} else if hasAllow {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user