Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 45 additions & 7 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ type GlobalConfig struct {
}

type FeatureConfig struct {
Scuba ScubaFeatureConfig `yaml:"scuba"`
BucketNotifications BucketNotificationsFeatureConfig `yaml:"bucket_notifications"`
Scuba ScubaFeatureConfig `yaml:"scuba"`
BucketNotifications BucketNotificationsFeatureConfig `yaml:"bucket_notifications"`
CrossRegionReplication CrossRegionReplicationFeatureConfig `yaml:"cross_region_replication"`
Utapi UtapiFeatureConfig `yaml:"utapi"`
Migration MigrationFeatureConfig `yaml:"migration"`
AccessLogging AccessLoggingFeatureConfig `yaml:"access_logging"`
S3Frontend S3FrontendFeatureConfig `yaml:"s3_frontend"`
Lifecycle LifecycleFeatureConfig `yaml:"lifecycle"`
Utapi UtapiFeatureConfig `yaml:"utapi"`
Migration MigrationFeatureConfig `yaml:"migration"`
AccessLogging AccessLoggingFeatureConfig `yaml:"access_logging"`
S3Frontend S3FrontendFeatureConfig `yaml:"s3_frontend"`
Lifecycle LifecycleFeatureConfig `yaml:"lifecycle"`
RateLimiting RateLimitingFeatureConfig `yaml:"rate_limiting"`
}

type S3FrontendFeatureConfig struct {
Expand Down Expand Up @@ -245,6 +246,29 @@ type LifecycleFeatureConfig struct {
Enabled bool `yaml:"enabled"`
}

type RateLimitingFeatureConfig struct {
Enabled bool `yaml:"enabled"`
Bucket RateLimitingDefaultLimits `yaml:"bucket"`
Account RateLimitingDefaultLimits `yaml:"account"`
Error RateLimitingErrorConfig `yaml:"error"`
}

type RateLimitingDefaultLimits struct {
RequestsPerSecond *RateLimitingLimitConfig `yaml:"requests_per_second"`
ConfigCacheTTL int `yaml:"config_cache_ttl"`
}

type RateLimitingLimitConfig struct {
Limit int `yaml:"limit"`
BurstCapacity int `yaml:"burst_capacity"`
}

type RateLimitingErrorConfig struct {
StatusCode int `yaml:"status_code"`
Code string `yaml:"code"`
Message string `yaml:"message"`
}

func DefaultEnvironmentConfig() EnvironmentConfig {
return EnvironmentConfig{
Global: GlobalConfig{
Expand Down Expand Up @@ -275,6 +299,20 @@ func DefaultEnvironmentConfig() EnvironmentConfig {
Lifecycle: LifecycleFeatureConfig{
Enabled: false,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every other feature in DefaultEnvironmentConfig() explicitly sets Enabled: false (e.g., Utapi, Migration, Lifecycle). While Go's zero value handles this correctly, adding it here keeps the defaults self-documenting and consistent.

Suggested change
},
RateLimiting: RateLimitingFeatureConfig{
Enabled: false,
Bucket: RateLimitingDefaultLimits{

— Claude Code

RateLimiting: RateLimitingFeatureConfig{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate limiting requires Redis (via localCache), but the Redis service in docker-compose.yaml does not include a feature-rate-limiting profile. If a user enables only rate limiting (without utapi, CRR, etc.), Redis won't start and cloudserver will fail to connect. A feature-rate-limiting profile needs to be added to the Redis service, and getComposeProfiles in cmd/util.go needs a corresponding entry for RateLimiting.Enabled.

— Claude Code

Enabled: false,
Bucket: RateLimitingDefaultLimits{
ConfigCacheTTL: 30000,
},
Account: RateLimitingDefaultLimits{
ConfigCacheTTL: 30000,
},
Error: RateLimitingErrorConfig{
StatusCode: 429,
Code: "SlowDown",
Message: "Rate limit exceeded. Please try again later.",
},
},
},
Cloudserver: CloudserverConfig{},
S3Metadata: MetadataConfig{
Expand Down
13 changes: 7 additions & 6 deletions cmd/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,13 @@ func generateCloudserverConfig(cfg EnvironmentConfig, path string) error {
return err
}

return renderTemplateToFile(
getTemplates(),
"templates/cloudserver/locationConfig.json",
cfg,
filepath.Join(path, "cloudserver", "locationConfig.json"),
)
templates := []string{
"locationConfig.json",
"create-service-user.sh",
"Dockerfile.setup",
}

return renderTemplates(cfg, "templates/cloudserver", filepath.Join(path, "cloudserver"), templates)
}

func generateBackbeatConfig(cfg EnvironmentConfig, path string) error {
Expand Down
7 changes: 6 additions & 1 deletion cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"
"text/template"

"github.com/Masterminds/sprig/v3"
"github.com/hashicorp/go-multierror"

"github.com/scality/workbench"
Expand All @@ -25,7 +26,7 @@ func getTemplates() fs.FS {
}

func templateFile(templates fs.FS, path string, data any) ([]byte, error) {
tmpl, err := template.ParseFS(templates, path)
tmpl, err := template.New(filepath.Base(path)).Funcs(sprig.FuncMap()).ParseFS(templates, path)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -100,6 +101,10 @@ func getComposeProfiles(cfg EnvironmentConfig) []string {
profiles = append(profiles, "feature-lifecycle")
}

if cfg.Features.RateLimiting.Enabled {
profiles = append(profiles, "feature-rate-limiting")
}

return profiles
}

Expand Down
12 changes: 11 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@ go 1.24.3

require (
dario.cat/mergo v1.0.2
github.com/Masterminds/sprig/v3 v3.3.0
github.com/alecthomas/kong v1.11.0
github.com/hashicorp/go-multierror v1.1.1
github.com/rs/zerolog v1.34.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
golang.org/x/sys v0.12.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sys v0.23.0 // indirect
)
41 changes: 40 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
@@ -1,33 +1,72 @@
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v1.11.0 h1:y++1gI7jf8O7G7l4LZo5ASFhrhJvzc+WgF/arranEmM=
github.com/alecthomas/kong v1.11.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 changes: 11 additions & 0 deletions templates/cloudserver/Dockerfile.setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
ARG BASE_IMAGE

FROM $BASE_IMAGE

USER root

RUN apt-get update && apt-get install -y jq curl

COPY --chmod=755 create-service-user.sh /opt/

CMD ["/opt/create-service-user.sh"]
40 changes: 38 additions & 2 deletions templates/cloudserver/config-v7.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@
{{ else }}
"bucketNotificationDestinations": [],
{{ end }}
{{ if .Features.Utapi.Enabled }}
{{ if or .Features.Utapi.Enabled .Features.RateLimiting.Enabled }}
"localCache": {
"host": "localhost",
"port": 6379
},
{{ end }}
{{ if .Features.Utapi.Enabled }}
"utapi": {
"host": "localhost",
"port": 8100,
Expand All @@ -112,6 +114,40 @@
"port": 6379
}
},
{{ end }}
{{- end }}
{{- if .Features.RateLimiting.Enabled }}
"rateLimiting": {
"enabled": {{ .Features.RateLimiting.Enabled }},
"serviceUserArn": "arn:aws:iam::000000000000:user/scality-internal/service-rate-limit-user",
"nodes": 1,
"bucket": {
{{- if .Features.RateLimiting.Bucket.RequestsPerSecond }}
"defaultConfig": {
"requestsPerSecond": {
"limit": {{ .Features.RateLimiting.Bucket.RequestsPerSecond.Limit }},
"burstCapacity": {{ .Features.RateLimiting.Bucket.RequestsPerSecond.BurstCapacity }}
}
},
{{- end }}
"configCacheTTL": {{ .Features.RateLimiting.Bucket.ConfigCacheTTL }}
},
"account": {
{{- if .Features.RateLimiting.Account.RequestsPerSecond }}
"defaultConfig": {
"requestsPerSecond": {
"limit": {{ .Features.RateLimiting.Account.RequestsPerSecond.Limit }},
"burstCapacity": {{ .Features.RateLimiting.Account.RequestsPerSecond.BurstCapacity }}
}
},
{{- end }}
"configCacheTTL": {{ .Features.RateLimiting.Account.ConfigCacheTTL }}
},
"error": {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same hardcoded configCacheTTL issue as in config-v9.json — should use {{ .Features.RateLimiting.Account.ConfigCacheTTL }} to respect user config.

Suggested change
"error": {
"configCacheTTL": {{ .Features.RateLimiting.Account.ConfigCacheTTL }}

— Claude Code

"statusCode": {{ .Features.RateLimiting.Error.StatusCode }},
"code": {{ .Features.RateLimiting.Error.Code | toJson }},
"message": {{ .Features.RateLimiting.Error.Message | toJson }}
}
},
{{- end }}
"testingMode": true
}
38 changes: 37 additions & 1 deletion templates/cloudserver/config-v9.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@
{{ else }}
"bucketNotificationDestinations": [],
{{ end }}
{{ if .Features.Utapi.Enabled }}
{{ if or .Features.Utapi.Enabled .Features.RateLimiting.Enabled }}
"localCache": {
"host": "localhost",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The templates now require Redis (localCache) when rate limiting is enabled, but the Redis service in docker-compose.yaml does not include a rate-limiting profile, and getComposeProfiles() in cmd/util.go has no entry for features.rate_limiting. If a user enables only rate limiting (no utapi, crr, notifications, migration, or lifecycle), Redis will not start and cloudserver will fail to connect.

You need to: (1) add a profile like feature-rate-limiting to the Redis service in docker-compose.yaml, and (2) add a corresponding block in getComposeProfiles() to activate it when cfg.Features.RateLimiting.Enabled is true.

— Claude Code

"port": 6379
},
{{ end }}
{{ if .Features.Utapi.Enabled }}
"utapi": {
"host": "localhost",
"port": 8100,
Expand Down Expand Up @@ -195,5 +197,39 @@
"retryReopenDelayMS": 1000,
"checkFileRotationIntervalMS": 10000
},
{{- if .Features.RateLimiting.Enabled }}
"rateLimiting": {
"enabled": {{ .Features.RateLimiting.Enabled }},
"serviceUserArn": "arn:aws:iam::000000000000:user/scality-internal/service-rate-limit-user",
"nodes": 1,
"bucket": {
{{- if .Features.RateLimiting.Bucket.RequestsPerSecond }}
"defaultConfig": {
"requestsPerSecond": {
"limit": {{ .Features.RateLimiting.Bucket.RequestsPerSecond.Limit }},
"burstCapacity": {{ .Features.RateLimiting.Bucket.RequestsPerSecond.BurstCapacity }}
}
},
{{- end }}
"configCacheTTL": {{ .Features.RateLimiting.Bucket.ConfigCacheTTL }}
},
"account": {
{{- if .Features.RateLimiting.Account.RequestsPerSecond }}
"defaultConfig": {
"requestsPerSecond": {
"limit": {{ .Features.RateLimiting.Account.RequestsPerSecond.Limit }},
"burstCapacity": {{ .Features.RateLimiting.Account.RequestsPerSecond.BurstCapacity }}
}
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configCacheTTL is hardcoded to 30000 here instead of using the template variable. The bucket section correctly uses {{ .Features.RateLimiting.Bucket.ConfigCacheTTL }}, but the account section ignores the config value.

Suggested change
},
"configCacheTTL": {{ .Features.RateLimiting.Account.ConfigCacheTTL }}

— Claude Code

{{- end }}
"configCacheTTL": {{ .Features.RateLimiting.Account.ConfigCacheTTL }}
},
"error": {
"statusCode": {{ .Features.RateLimiting.Error.StatusCode }},
"code": {{ .Features.RateLimiting.Error.Code | toJson }},
"message": {{ .Features.RateLimiting.Error.Message | toJson }}
}
},
{{- end }}
"testingMode": true
}
25 changes: 25 additions & 0 deletions templates/cloudserver/create-service-user.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env sh
set -xe

MANAGEMENT_ACCESS_KEY=$(jq -r '.accessKey' /secrets/management-creds.json)
MANAGEMENT_SECRET_KEY=$(jq -r '.secretKey' /secrets/management-creds.json)

# === Create rate-limit service user ===
echo "[setup] Creating rate-limit service user..."
SERVICE_CREDS_JSON=$(AWS_ACCESS_KEY_ID="$MANAGEMENT_ACCESS_KEY" \
AWS_SECRET_ACCESS_KEY="$MANAGEMENT_SECRET_KEY" \
AWS_REGION="us-east-1" \
./bin/ensureServiceUser apply service-rate-limit-user --iam-endpoint http://127.0.0.1:8600)

SERVICE_ACCESS_KEY=$(echo "$SERVICE_CREDS_JSON" | jq -r '.data.AccessKeyId')
SERVICE_SECRET_KEY=$(echo "$SERVICE_CREDS_JSON" | jq -r '.data.SecretAccessKey')

echo "[setup] rate-limit service user credentials:"
echo "SERVICE_ACCESS_KEY=$SERVICE_ACCESS_KEY"
echo "SERVICE_SECRET_KEY=$SERVICE_SECRET_KEY"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Service credentials (access key and secret key) are echoed to stdout on lines 19-20, which will appear in container logs. This matches the existing pattern in templates/scuba/create-service-user.sh, but it's worth noting that anyone with access to container logs can read these internal service credentials.

— Claude Code

echo

# === Update rate-limit-service-creds.json ===
echo "[setup] Updating rate-limit-service-creds.json with service user credentials..."
jq --null-input --arg ak "$SERVICE_ACCESS_KEY" --arg sk "$SERVICE_SECRET_KEY" \
'{accessKey: $ak, secretKey: $sk}' > /secrets/rate-limit-service-creds.json
Loading
Loading