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
+18 -2
View File
@@ -9,7 +9,9 @@ import (
"encoding/json"
"encoding/pem"
"io"
"net"
"net/http"
"net/url"
"sync"
"time"
@@ -20,6 +22,7 @@ import (
zhttp "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/api/oidc/sign"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/denylist"
"github.com/zitadel/zitadel/internal/domain"
target_domain "github.com/zitadel/zitadel/internal/execution/target"
"github.com/zitadel/zitadel/internal/repository/execution"
@@ -43,7 +46,8 @@ func CallTargets(
info ContextInfo,
alg crypto.EncryptionAlgorithm,
activeSigningKey GetActiveSigningWebKey,
) (_ interface{}, err error) {
deniedIPList []denylist.AddressChecker,
) (_ any, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -54,7 +58,7 @@ func CallTargets(
for _, target := range targets {
// call the type of target
resp, err := CallTarget(ctx, target, info, alg, signerOnce, encrypters)
resp, err := CallTarget(ctx, target, info, alg, signerOnce, encrypters, deniedIPList)
// handle error if interrupt is set
logging.WithFields("instanceID", authz.GetInstance(ctx).InstanceID(), "target", target.GetTargetID()).OnError(err).Error("error calling target")
if err != nil && target.IsInterruptOnError() {
@@ -82,6 +86,7 @@ func CallTarget(
alg crypto.EncryptionAlgorithm,
signerOnce sign.SignerFunc,
encrypters *sync.Map,
deniedIPList []denylist.AddressChecker,
) (res []byte, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -90,6 +95,17 @@ func CallTarget(
if err != nil {
return nil, zerrors.ThrowInternal(err, "EXEC-thiiCh5b", "Errors.Internal")
}
if target.GetEndpoint() != "" {
endpointURL, err := url.Parse(target.GetEndpoint())
if err != nil {
return nil, zerrors.ThrowInvalidArgument(err, "EXEC-N5lu09", "Errors.Endpoint.Invalid")
}
if err := denylist.IsHostBlocked(deniedIPList, endpointURL, net.LookupIP); err != nil {
return nil, zerrors.ThrowInvalidArgument(err, "EXEC-N5lu09", "Errors.Endpoint.Denied")
}
}
body, err := payload(ctx, info.GetHTTPRequestBody(), target, signerOnce, encrypters)
if err != nil {
return nil, err