Add session policy support to IAM (#8338)

* Add session policy support to IAM

- Implement policy evaluation for session tokens in policy_engine.go
- Add session_policy field to session claims for tracking applied policies
- Update STS service to include session policies in token generation
- Add IAM integration tests for session policy validation
- Update IAM manager to support policy attachment to sessions
- Extend S3 API STS endpoint to handle session policy restrictions

* fix: optimize session policy evaluation and add documentation

* sts: add NormalizeSessionPolicy helper for inline session policies

* sts: support inline session policies for AssumeRoleWithWebIdentity and credential-based flows

* s3api: parse and normalize Policy parameter for STS HTTP handlers

* tests: add session policy unit tests and integration tests for inline policy downscoping

* tests: add s3tables STS inline policy integration

* iam: handle user principals and validate tokens

* sts: enforce inline session policy size limit

* tests: harden s3tables STS integration config

* iam: clarify principal policy resolution errors

* tests: improve STS integration endpoint selection
This commit is contained in:
Chris Lu
2026-02-13 13:58:22 -08:00
committed by GitHub
parent beeb375a88
commit 49a64f50f1
12 changed files with 682 additions and 275 deletions

View File

@@ -474,6 +474,68 @@ func (e *PolicyEngine) EvaluateTrustPolicy(ctx context.Context, trustPolicy *Pol
return result, nil
}
// EvaluatePolicyDocument evaluates a single policy document without storing it.
// defaultEffect controls the fallback result when no statements match.
func (e *PolicyEngine) EvaluatePolicyDocument(ctx context.Context, evalCtx *EvaluationContext, policyName string, policyDoc *PolicyDocument, defaultEffect Effect) (*EvaluationResult, error) {
if !e.initialized {
return nil, fmt.Errorf("policy engine not initialized")
}
if evalCtx == nil {
return nil, fmt.Errorf("evaluation context cannot be nil")
}
if policyDoc == nil {
return nil, fmt.Errorf("policy document cannot be nil")
}
if policyName == "" {
policyName = "inline-policy"
}
result := &EvaluationResult{
Effect: defaultEffect,
EvaluationDetails: &EvaluationDetails{
Principal: evalCtx.Principal,
Action: evalCtx.Action,
Resource: evalCtx.Resource,
PoliciesEvaluated: []string{policyName},
},
}
var matchingStatements []StatementMatch
explicitDeny := false
hasAllow := false
for _, statement := range policyDoc.Statement {
if e.statementMatches(&statement, evalCtx) {
match := StatementMatch{
PolicyName: policyName,
StatementSid: statement.Sid,
Effect: Effect(statement.Effect),
Reason: "Action, Resource, and Condition matched",
}
matchingStatements = append(matchingStatements, match)
if statement.Effect == "Deny" {
explicitDeny = true
} else if statement.Effect == "Allow" {
hasAllow = true
}
}
}
result.MatchingStatements = matchingStatements
if explicitDeny {
result.Effect = EffectDeny
} else if hasAllow {
result.Effect = EffectAllow
}
return result, nil
}
// statementMatches checks if a statement matches the evaluation context
func (e *PolicyEngine) statementMatches(statement *Statement, evalCtx *EvaluationContext) bool {
// Check principal match (for trust policies)