Browse Source

fix(sts): make secret access key deterministic based on sessionId

CRITICAL FIX: The secret access key was being randomly generated, causing
signature verification failures when the same session token was used twice:

1. AssumeRoleWithWebIdentity generates random secret key X
2. Client signs request using secret key X
3. Server validates token, regenerates credentials via ToSessionInfo()
4. ToSessionInfo() calls generateSecretAccessKey(), which generates random key Y
5. Server tries to verify signature using key Y, but signature was made with X
6. Signature verification fails (SignatureDoesNotMatch)

Solution: Make generateSecretAccessKey() deterministic by using SHA256 hash
of 'secret-key:' + sessionId, just like generateAccessKeyId() already does.

This ensures:
- AssumeRoleWithWebIdentity generates deterministic secret key from sessionId
- ToSessionInfo() regenerates the same secret key from the same sessionId
- Client signature verification succeeds because keys match

Fixes: AWS SDK v2 CORS tests failing with 'ExpiredToken' errors
Affected files:
- weed/iam/sts/token_utils.go: Updated generateSecretAccessKey() signature
  and implementation to be deterministic
- Updated GenerateTemporaryCredentials() to pass sessionId parameter

Tests: All 54 STS tests pass with this fix
pull/7944/head
Chris Lu 1 month ago
parent
commit
1dc94e92f6
  1. 22
      weed/iam/sts/token_utils.go
  2. 3
      weed/s3api/auth_signature_v4.go

22
weed/iam/sts/token_utils.go

@ -149,7 +149,7 @@ func (c *CredentialGenerator) GenerateTemporaryCredentials(sessionId string, exp
return nil, fmt.Errorf("failed to generate access key ID: %w", err)
}
secretAccessKey, err := c.generateSecretAccessKey()
secretAccessKey, err := c.generateSecretAccessKey(sessionId)
if err != nil {
return nil, fmt.Errorf("failed to generate secret access key: %w", err)
}
@ -174,16 +174,16 @@ func (c *CredentialGenerator) generateAccessKeyId(sessionId string) (string, err
return "AKIA" + hex.EncodeToString(hash[:8]), nil // AWS format: AKIA + 16 chars
}
// generateSecretAccessKey generates a random secret access key
func (c *CredentialGenerator) generateSecretAccessKey() (string, error) {
// Generate 32 random bytes for secret key
secretBytes := make([]byte, 32)
_, err := rand.Read(secretBytes)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(secretBytes), nil
// generateSecretAccessKey generates a deterministic secret access key based on sessionId
// This ensures the same secret key is regenerated from the JWT claims during signature verification
func (c *CredentialGenerator) generateSecretAccessKey(sessionId string) (string, error) {
// Create deterministic secret key based on session ID (not random!)
// This is critical for STS because:
// 1. AssumeRoleWithWebIdentity generates the secret key once
// 2. During signature verification, ToSessionInfo() regenerates credentials from JWT
// 3. Both must generate the same secret key for signature verification to succeed
hash := sha256.Sum256([]byte("secret-key:" + sessionId))
return base64.StdEncoding.EncodeToString(hash[:]), nil
}
// generateSessionTokenId generates a session token identifier

3
weed/s3api/auth_signature_v4.go

@ -233,7 +233,8 @@ func (iam *IdentityAccessManagement) verifyV4Signature(r *http.Request, shouldCh
glog.Warningf("InvalidAccessKeyId: attempted key '%s' not found. Available keys: %d, Auth enabled: %v",
authInfo.AccessKey, len(availableKeys), iam.isAuthEnabled)
return nil, nil, "", nil, s3err.ErrInvalidAccessKeyID }
return nil, nil, "", nil, s3err.ErrInvalidAccessKeyID
}
// Check service account expiration
if cred.isCredentialExpired() {

Loading…
Cancel
Save