Merge commit from fork

* Inject DenyList from config to `StartCommands()`

* Implementation draft

* Move address checker to separate package

* Migrate usages of actions.AddressChecker to denylist.AddressChecker

* Rename denylist package files

* Pass []denylist.AddressChecker to StartCommand

* Add DenyList to defaults.yaml and add custom config parser

* net: add HostnameToIPList function

* denylist: Add IsHostBlocked()

* actions: use denylist.IsHostBlocked()

* command: Inject ip lookup function + extend add target validationt test

* command: Unexport ChangeTarget.IsValid()

* command: Add denyList check on ChangeTarget validation

* command: Export ActionsV2DenyList and IPLookupFunction params

* Lint fix

* Check denylist during action execution

* Fix integration tests

* Apply suggestions

* Add `mapstructure.StringToSliceHookFunc()` to decode `HTTPConfigDecodeHook`
This commit is contained in:
Marco A.
2026-02-25 06:33:28 +01:00
committed by GitHub
parent bac224c56d
commit b2532e9666
38 changed files with 823 additions and 292 deletions
+8
View File
@@ -574,6 +574,14 @@ Executions:
TransactionDuration: 10s # ZITADEL_EXECUTIONS_TRANSACTIONDURATION
# Automatically cancel the notification if it cannot be handled within a specific time
MaxTtl: 5m # ZITADEL_EXECUTIONS_MAXTTL
# List of domains and IPs that are not valid execution target's endpoints
# Wildcard sub domains are currently unsupported
DenyList: # ZITADEL_EXECUTIONS_DENYLIST (comma separated list)
- localhost
- "127.0.0.0/8"
- "::1"
- "0.0.0.0"
- "::"
Auth:
# See Projections.BulkLimit
+2
View File
@@ -18,6 +18,7 @@ import (
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/hook"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/id"
)
@@ -100,6 +101,7 @@ func newConfig(v *viper.Viper, config any) error {
mapstructure.StringToSliceHookFunc(","),
database.DecodeHook(true),
actions.HTTPConfigDecodeHook,
denylist.DenyListDecodeHook,
hook.EnumHookFunc(internal_authz.MemberTypeString),
mapstructure.TextUnmarshallerHookFunc(),
)),
+2
View File
@@ -34,6 +34,7 @@ import (
"github.com/zitadel/zitadel/internal/config/systemdefaults"
crypto_db "github.com/zitadel/zitadel/internal/crypto/database"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
old_es "github.com/zitadel/zitadel/internal/eventstore/repository/sql"
@@ -215,6 +216,7 @@ func projections(
config.OIDC.DefaultRefreshTokenIdleExpiration,
config.DefaultInstance.SecretGenerators,
config.Login.DefaultPaths,
[]denylist.AddressChecker{},
)
logging.OnError(ctx, err).Fatal("unable to start commands")
+2
View File
@@ -16,6 +16,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
crypto_db "github.com/zitadel/zitadel/internal/crypto/database"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
)
@@ -96,6 +97,7 @@ func (mig *FirstInstance) Execute(ctx context.Context, _ eventstore.Event) error
0,
nil,
mig.defaultPaths,
[]denylist.AddressChecker{},
)
if err != nil {
return err
+2
View File
@@ -26,6 +26,7 @@ import (
"github.com/zitadel/zitadel/internal/config/hook"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/execution"
@@ -81,6 +82,7 @@ func NewConfig(cmd *cobra.Command, v *viper.Viper) (*Config, instrumentation.Shu
hooks.MapTypeStringDecode[string, *authz.SystemAPIUser],
hooks.MapHTTPHeaderStringDecode,
database.DecodeHook(false),
denylist.DenyListDecodeHook,
actions.HTTPConfigDecodeHook,
hook.EnumHookFunc(authz.MemberTypeString),
hook.Base64ToBytesHookFunc(),
+2
View File
@@ -7,6 +7,7 @@ import (
"github.com/zitadel/zitadel/internal/cache/connector"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/eventstore"
)
@@ -60,6 +61,7 @@ func (mig *externalConfigChange) Execute(ctx context.Context, _ eventstore.Event
0,
nil,
&login.DefaultPaths{},
[]denylist.AddressChecker{},
)
if err != nil {
+1
View File
@@ -575,6 +575,7 @@ func startCommandsQueries(
config.OIDC.DefaultRefreshTokenIdleExpiration,
config.DefaultInstance.SecretGenerators,
config.Login.DefaultPaths,
config.Executions.DenyList,
)
logging.OnError(ctx, err).Fatal("unable to start commands")
+2
View File
@@ -30,6 +30,7 @@ import (
"github.com/zitadel/zitadel/internal/config/network"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/execution"
@@ -146,6 +147,7 @@ func readConfig(v *viper.Viper) (*Config, error) {
hooks.MapHTTPHeaderStringDecode,
database.DecodeHook(false),
actions.HTTPConfigDecodeHook,
denylist.DenyListDecodeHook,
hook.EnumHookFunc(authz.MemberTypeString),
hooks.MapTypeStringDecode[domain.Feature, any],
hooks.SliceTypeStringDecode[*command.SetQuota],
+9 -9
View File
@@ -14,9 +14,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/actions"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/feature"
)
@@ -48,10 +48,10 @@ Log:
Level: info
`},
want: func(t *testing.T, config *Config) {
assert.Equal(t, config.Actions.HTTP.DenyList, []actions.AddressChecker{
&actions.HostChecker{Domain: "localhost"},
&actions.HostChecker{IP: net.ParseIP("127.0.0.1")},
&actions.HostChecker{Domain: "foobar"}})
assert.Equal(t, config.Actions.HTTP.DenyList, []denylist.AddressChecker{
&denylist.HostChecker{Domain: "localhost"},
&denylist.HostChecker{IP: net.ParseIP("127.0.0.1")},
&denylist.HostChecker{Domain: "foobar"}})
},
}, {
name: "actions deny list string ok",
@@ -64,10 +64,10 @@ Log:
Level: info
`},
want: func(t *testing.T, config *Config) {
assert.Equal(t, config.Actions.HTTP.DenyList, []actions.AddressChecker{
&actions.HostChecker{Domain: "localhost"},
&actions.HostChecker{IP: net.ParseIP("127.0.0.1")},
&actions.HostChecker{Domain: "foobar"}})
assert.Equal(t, config.Actions.HTTP.DenyList, []denylist.AddressChecker{
&denylist.HostChecker{Domain: "localhost"},
&denylist.HostChecker{IP: net.ParseIP("127.0.0.1")},
&denylist.HostChecker{Domain: "foobar"}})
},
}, {
name: "features ok",
+2
View File
@@ -289,6 +289,7 @@ func startZitadel(ctx context.Context, config *Config, masterKey string, server
config.OIDC.DefaultRefreshTokenIdleExpiration,
config.DefaultInstance.SecretGenerators,
config.Login.DefaultPaths,
config.Executions.DenyList,
)
if err != nil {
return fmt.Errorf("cannot start commands: %w", err)
@@ -478,6 +479,7 @@ func startAPIs(
keys.Target,
translator,
config.Instrumentation.Trace.TrustRemoteSpans,
config.Executions.DenyList,
)
if err != nil {
return nil, fmt.Errorf("error creating api %w", err)