mirror of
https://github.com/versity/versitygw.git
synced 2026-09-27 18:34:25 +00:00
Implements the `AssumeRoleWithWebIdentity` and `GetCallerIdentity` STS actions, letting callers exchange an external OIDC token for temporary credentials scoped to an IAM role. Token handling covers JWT claim parsing, issuer/audience resolution (including `azp` override semantics), JWKS fetching and caching with `singleflight`-deduplicated refresh, and rate-limited forced refresh on unrecognized `kid` values. OIDC provider thumbprint fetching now performs a real TLS handshake verified against the system trust store and the provider hostname (previously `InsecureSkipVerify`), since the observed certificate is persisted as a long-lived trust anchor rather than used once and discarded; all discovery-document and JWKS fetches go through an SSRF-safe HTTP client with bounded redirects and response size.
Adds policy `Condition` block evaluation, supporting `String`, `Numeric`, `Date`, `Bool`, `BinaryEquals`, and `IpAddress` operators along with their `IfExists`/`Not` variants and `ForAllValues`/`ForAnyValues` set qualifiers, plus policy variable substitution (e.g. `${aws:username}`) in supported operators. Adds identity-based inline policy evaluation and a new IAM authorization middleware that authorizes each request against action, resource, and condition context together, applying the session-policy-intersects-role-policy semantics for assumed-role sessions.
Adds a new debug logger `--log-level` flag (`silent`/`debug`/`unsafe`), along with a tree-based XML masker that redacts secrets and tokens at the property level in logged request/response bodies instead of skipping the whole body. The old `--debug/VGW_DEBUG` flag is kept as a deprecated alias for `--log-level=debug`, printing a console warning that points users at `--log-level` for finer-grained control.
Fixes a Vault storage bug where CAS (check-and-set) writes always read the current document version as 0 because `kvVersion` asserted metadata as `float64` while the Vault client actually returns `json.Number`, causing every write past the first to be rejected as a concurrent modification. Also adds a constant-time `SecureCompare` for signature/token comparisons in sigv4 auth.
Adds an integration test suite (`iam_access_control.go`) covering IAM access control across user, role, and session identities.
116 lines
2.1 KiB
Go
116 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/versity/versitygw/backend/meta"
|
|
"github.com/versity/versitygw/backend/posix"
|
|
"github.com/versity/versitygw/cmd/internal/gwcli"
|
|
"github.com/versity/versitygw/tests/integration"
|
|
)
|
|
|
|
const (
|
|
tdir = "tempdir"
|
|
)
|
|
|
|
var (
|
|
wg sync.WaitGroup
|
|
)
|
|
|
|
func initEnv(dir string) {
|
|
// both
|
|
logLevel = "debug"
|
|
region = "us-east-1"
|
|
|
|
// server
|
|
gwcli.RootUserAccess = "user"
|
|
gwcli.RootUserSecret = "pass"
|
|
iamDir = dir
|
|
maxConnections = 250000
|
|
maxRequests = 100000
|
|
ports = []string{"127.0.0.1:7070"}
|
|
mpMaxParts = 10000
|
|
gwcli.CopyObjectThreshold = 5 * 1024 * 1024 * 1024
|
|
|
|
// client
|
|
awsID = "user"
|
|
awsSecret = "pass"
|
|
endpoint = "http://127.0.0.1:7070"
|
|
}
|
|
|
|
func initPosix(ctx context.Context) {
|
|
path, err := os.Getwd()
|
|
if err != nil {
|
|
log.Fatalf("get current directory: %v", err)
|
|
}
|
|
|
|
tempdir := filepath.Join(path, tdir)
|
|
initEnv(tempdir)
|
|
|
|
err = os.RemoveAll(tempdir)
|
|
if err != nil {
|
|
log.Fatalf("remove temp directory: %v", err)
|
|
}
|
|
|
|
err = os.Mkdir(tempdir, 0755)
|
|
if err != nil {
|
|
log.Fatalf("make temp directory: %v", err)
|
|
}
|
|
|
|
be, err := posix.New(tempdir, meta.XattrMeta{}, posix.PosixOpts{
|
|
NewDirPerm: 0755,
|
|
Concurrency: 5000,
|
|
})
|
|
if err != nil {
|
|
log.Fatalf("init posix: %v", err)
|
|
}
|
|
|
|
wg.Go(func() {
|
|
err = runGateway(ctx, be)
|
|
if err != nil && err != context.Canceled {
|
|
log.Fatalf("run gateway: %v", err)
|
|
}
|
|
|
|
err := os.RemoveAll(tempdir)
|
|
if err != nil {
|
|
log.Fatalf("remove temp directory: %v", err)
|
|
}
|
|
})
|
|
|
|
// wait for server to start
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
|
|
func TestIntegration(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
initPosix(ctx)
|
|
|
|
opts := []integration.Option{
|
|
integration.WithAccess(awsID),
|
|
integration.WithSecret(awsSecret),
|
|
integration.WithRegion(region),
|
|
integration.WithEndpoint(endpoint),
|
|
}
|
|
if logLevel != "silent" && logLevel != "" {
|
|
opts = append(opts, integration.WithDebug())
|
|
}
|
|
|
|
s := integration.NewS3Conf(opts...)
|
|
|
|
// replace below with desired test
|
|
err := integration.HeadBucket_non_existing_bucket(s)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
cancel()
|
|
wg.Wait()
|
|
}
|