Connector Destinations
A connector registered by endpoint is a service that Kamiwaza calls at a URL an administrator supplies. Kamiwaza calls it from inside the cluster, so an unchecked endpoint could point Kamiwaza at its own internal services or at a cloud metadata service. From Kamiwaza 1.4, Kamiwaza checks every connector endpoint before it connects:
- At registration and subscription (
POST /api/connectors/registerandPOST /api/connectors/subscriptions), before Kamiwaza contacts the endpoint or stores it. - On every later call to a stored endpoint: execute, verify, whoami and the manifest refresh after a settings change. Kamiwaza resolves the host again on each call, checks every address it gets, and connects only to an address it checked. A hostname that later resolves to a private address (DNS rebinding) is refused.
Connectors that Kamiwaza deployed itself, such as those in Run Your Own Connector, keep working: Kamiwaza admits the exact Service it deployed for that connector.
What a connector may reach
A connector endpoint is admitted when it resolves only to:
- public internet addresses;
- a host, domain or address range the operator lists site-wide (see Site-wide allowlist);
- a
host:portan administrator approved for that connector (see Per-connector approved destinations); or - for calls to a stored endpoint, the Service Kamiwaza deployed for that connector.
Everything else is refused. That includes private (RFC 1918), CGNAT, site-local and other non-public addresses, which you can admit with a listing or an approval.
The floor
Some addresses are refused even when they are listed or approved:
- loopback (
127.0.0.0/8,::1) and0.0.0.0/8; - link-local addresses;
- cloud metadata services:
169.254.169.254, AWSfd00:ec2::254andfd00:ec2::23, GCPfd20:ce::254, OCIfd00:c1::a9fe:a9fe, Azure WireServer168.63.129.16and Alibaba100.100.100.200; - unspecified, multicast and reserved addresses, Teredo (
2001::/32), and NAT64 addresses in64:ff9b::/32other than the well-known64:ff9b::/96.
The 0.0.0.0/8 and cloud metadata refusals also apply to Kamiwaza's other
outbound destinations, so an external model endpoint or a custom S3 endpoint
cannot target them either.
The only way past the floor is the
development-only override, which an install refuses under the
production environment and the stig security profile.
Endpoint URL rules
A connector endpoint must:
- use
httporhttps; - carry no credentials (
user:password@), query string or fragment; - name a host, as an ASCII hostname (letters, digits,
-,_and.). Give an internationalized name in its punycode (xn--) form; - contain no control characters or IPv6 zone (
%25...); - have a port from 1 to 65535, if it gives one.
An IP address is accepted only when it falls inside a CIDR that you
list site-wide. Legacy IPv4 spellings such as
2130706433 or 127.1 count as IP addresses.
A refused registration returns HTTP 400 with a message that says exactly what
is not allowed and names the setting that would admit it, for example:
Connector endpoint host 'crm.internal.example' is not allowed: it must resolve,
from Core, only to public addresses, or the host or its address must be listed
in KAMIWAZA_CONNECTOR_ENDPOINT_ALLOWLIST. Private and CGNAT addresses are
refused unless listed. ...
That setting is the Helm value core.connectors.endpointAllowlist (see
Site-wide allowlist).
Manifest fetch at registration
When you register a connector, Kamiwaza fetches <endpoint>/manifest. That
fetch:
- connects only to the address Kamiwaza checked;
- accepts only HTTP
200and does not follow redirects; - times out after 3 seconds to connect and 5 seconds per read, and gives up 10 seconds after it connects, whatever is still arriving;
- refuses compressed manifests and manifests over 1 MiB.
Every fetch failure returns the same message, so the response does not reveal
what is listening at an address. Kamiwaza logs the cause as
connector_manifest_fetch_failed, with the endpoint's scheme, host and port
only.
These connections ignore HTTP_PROXY and HTTPS_PROXY, like Kamiwaza's other
address-checked clients. A site that reaches connectors only through a forward
proxy cannot register them by endpoint; the failure log says proxy=ignored.
Site-wide allowlist
List internal hosts that any connector may reach with the Helm value
core.connectors.endpointAllowlist. It is empty by default. Each entry is one
of:
- a hostname, such as
connector.internal.example.com; - a domain suffix with a leading dot, such as
.kamiwaza.svc.cluster.local; - a CIDR, such as
10.20.0.0/16.
An entry has no scheme and no port. An exact host:port for one connector is a
per-connector approval instead.
core:
connectors:
endpointAllowlist:
- connector.internal.example.com
- .kamiwaza.svc.cluster.local
Apply it with helm upgrade --install and the same values files you installed
with. The chart renders the list as KAMIWAZA_CONNECTOR_ENDPOINT_ALLOWLIST on
core-api, the scheduler and the Ray head and workers.
The render fails when:
- an entry is a URL, a
host:port, a CIDR with a prefix out of range or characters an address cannot contain, or contains a comma or a space. Kamiwaza would reject the whole list and then fail every connector call; - you also set
KAMIWAZA_CONNECTOR_ENDPOINT_ALLOWLISTas acore.scheduler.extraEnv(orcore.scheduler.linuxNvidia.extraEnv) entry. Move the list into the value, one list item per comma-separated entry, and remove theextraEnventry. AnextraEnventry on its own still works while the value is empty.
The chart catches common mistakes only; Kamiwaza validates every entry in
full. An entry the chart lets through but Kamiwaza cannot parse, such as the
CIDR 12345::/64, renders and installs. Kamiwaza then rejects the whole list:
registration returns 500 naming the entry, connector calls fail with 500
naming the setting, and Kamiwaza logs connector_endpoint_allowlist_invalid
with the entry. Fix the entry and run helm upgrade again.
List as narrowly as you can. Each entry admits every connector to that destination:
- Prefer one host, or
.<namespace>.svc.cluster.localfor the namespace your connectors run in. - A cluster-wide
.svc.cluster.localalso admits the Kubernetes API, the platform's databases and every other Service. - A Service or pod CIDR admits every hostname that resolves into it.
- The two entries
0.0.0.0/0and::/0, each its own list item (an entry with a comma fails the render), restore the private-network reach connectors had before 1.4, for new registrations too, while still refusing the floor. They also admit the Kubernetes API, databases and every other internal host. Use them only as a last resort during an upgrade, and replace them with narrow entries. While any/0entry is listed, the scheduler logsconnector_endpoint_allowlist_wide_openwhen it starts.
Use the site-wide list for address ranges, domain suffixes and for registering a new connector at an internal host: a per-connector approval needs the connector to exist first. For one existing connector, an approval is narrower.
Per-connector approved destinations
An administrator can approve one exact host:port for one existing connector.
An approval:
- records who approved it, when, and why (a reason of 1 to 500 characters is
required), and emits a
kamiwaza.audit.sensitive_data.changeaudit event; - admits whatever non-floor address the host resolves to on each call, like a site-wide host entry. Approve only names whose DNS you control;
- relaxes the policy only down to the floor. A floor address,
localhost, or a host that includes a port is refused.
To review and revoke approvals in the console, open Settings > Connectors. Under Approved destinations by connector, each approval shows its destination, who approved it and when, and its reason. Approvals made by the upgrade show Grandfathered on upgrade. Select Revoke and give a reason.
A revoked approval admits nothing. It is kept as history, and the upgrade never restores it. To admit the destination again, approve it again; that adds a new approval.
Through the API, as an administrator:
# Approve one destination for one connector
curl -sS -X POST "$KAMIWAZA_URL/api/connectors/<connector id>/approved-destinations" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"host": "crm.internal.example", "port": 8443, "reason": "CRM connector, change 1234"}'
# List the connector's active approvals
curl -sS "$KAMIWAZA_URL/api/connectors/<connector id>/approved-destinations" \
-H "Authorization: Bearer $TOKEN"
# Revoke one (a reason is required)
curl -sS -X POST \
"$KAMIWAZA_URL/api/connectors/<connector id>/approved-destinations/<approval id>/revoke" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"reason": "CRM moved to a public endpoint"}'
Approving a floor IP address or localhost returns 409. A hostname is not
resolved when you approve it; the floor still applies to its addresses on
every call. A non-administrator gets 403 on
every route on this page.
Existing connectors on upgrade
When you upgrade to 1.4, existing connectors keep working without a site-wide
entry. On its first start with 1.4, core-api records the upgrade time before
it serves any request. Then core-api and the scheduler each run a one-time
pass, so an install without the scheduler is covered too. For every connector
that existed before the upgrade and whose stored endpoint now resolves to a
private, non-floor address, the pass approves that exact host:port for that
connector only.
These approvals:
- show as Grandfathered on upgrade under Settings > Connectors;
- are logged as
connector_destination_approvedand audited as a system change; - can be revoked like any other approval. A revoked approval stays revoked.
The pass ignores the site-wide allowlist, so if you listed a broad range for the upgrade, you can narrow it later without breaking a grandfathered connector.
The pass does not grandfather:
- Floor addresses or invalid stored URLs, for example with credentials, a query string or fragment, trailing whitespace, or a bad host or port. Re-register these connectors with a valid endpoint.
- Hosts that do not resolve during the pass, or whose Kubernetes ownership
lookup fails. Kamiwaza retries them at later starts for up to 7 days, then
logs
connector_destination_grandfather_expiredand leaves them for an administrator to approve. - Connectors registered after the upgrade. Admit their hosts site-wide or with an approval.
Until the first pass finishes, a few seconds after the first start, calls to those connectors are refused and recorded in the blocked destinations view. They succeed once their approvals exist.
At startup, the scheduler logs connector_endpoint_outside_policy for each
enabled connector whose endpoint is still refused, and
connector_endpoint_invalid for each one whose stored URL is invalid, with
advice to re-register it.
Blocked connector destinations
Every destination Kamiwaza refuses for a connector is recorded: the connector,
the host:port, the address class, the reason, when it was first and last
seen, and how many times. Repeat refusals update one row, and the list keeps at
most 1,000 rows. Each refusal is also logged as connector_destination_refusal
and counted in the kamiwaza.connectors.destination.refusals metric, by
error.type.
Administrators see the list in the console under Settings > Connectors
Blocked connector destinations, or with
GET /api/connectors/destination-refusals.
To admit a refused destination for its connector, select Allow this
destination for this connector and give a reason. That creates a
per-connector approval for exactly that host:port.
Through the API:
curl -sS -X POST "$KAMIWAZA_URL/api/connectors/destination-refusals/<refusal id>/approve" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"reason": "Approved after review, change 1234"}'
Some rows cannot be allowed. The console shows why, and the API returns 409:
| Shown | Why | What to do |
|---|---|---|
Never allowed: <address class> | The host resolves to a floor address. | Point the connector at another address. |
Invalid endpoint: re-register the connector | The stored URL breaks the URL rules. | Re-register the connector with a valid endpoint. |
Refused before resolution: see the Core log | Kamiwaza refused the call before it resolved an address, so there is no destination to approve. | Read the core-api log for the rule. |
Allowing a destination here does not change what the connector's caller saw: callers always get the same refusal error, whatever the cause.
Development-only floor override
For local development against a service on the developer's own machine, the
Helm value core.connectors.unsafeDevAllowLoopbackAndMetadata: true lets a
listed or approved destination also be loopback, link-local, cloud metadata or
0.0.0.0/8. Never use it on a shared install.
It works only on a development install:
- The render fails unless the effective
KAMIWAZA_ENV(global.environment, or acore.scheduler.extraEnventry) isdev,development,local,testortesting. A blank value counts asproduction, andcommunityanddefaultare not development. - The render fails under the
stigsecurity profile (global.securityProfileorcore.security.profileset tostig, or anextraEnvAUTH_SECURITY_PROFILEorKAMIWAZA_SECURITY_PROFILEofstig). core-apiand the scheduler refuse to start outside a developmentKAMIWAZA_ENVor whenAUTH_SECURITY_PROFILEisstig, withConnectorUnsafeDevOverrideRefused, so settingKAMIWAZA_CONNECTOR_UNSAFE_DEV_ALLOW_LOOPBACK_AND_METADATAby another route does not get around it.
While the override is on, the notes Helm prints after an install or upgrade
show WARNING: UNSAFE DEVELOPMENT SETTING, Kamiwaza logs a warning at startup, and
it logs UNSAFE connector_destination_floor_bypassed for every call it admits
below the floor. A development KAMIWAZA_ENV also relaxes Kamiwaza's other
production-only hardening.
Troubleshooting
| Symptom or log event | Meaning | Fix |
|---|---|---|
Registration returns 400 naming KAMIWAZA_CONNECTOR_ENDPOINT_ALLOWLIST | The endpoint resolves to a non-public address that is not listed. | List the host in core.connectors.endpointAllowlist, narrowly. |
Registration returns 400 about the URL | The endpoint breaks a URL rule. | Fix the URL. |
| Registration fails with a generic manifest error | The manifest fetch failed: refused, timed out, not 200, a redirect, compressed, or too large. | Read connector_manifest_fetch_failed in the core-api log. |
connector_destination_refused | A call to a stored endpoint was refused. | Check Blocked connector destinations, then allow it or list it. |
A connector call fails as a retryable transient_failure (503) | Kamiwaza could not confirm with Kubernetes that it deployed the Service the connector points at, so it sent nothing. | Retry. If it persists, list the host site-wide, or redeploy the connector. |
connector_endpoint_outside_policy at scheduler startup | An existing connector is still refused after the upgrade. | Approve it for that connector, or list it. |
connector_endpoint_invalid | The stored URL is invalid and is refused on every call. | Re-register the connector. |
connector_endpoint_allowlist_wide_open | A /0 entry is listed. | Replace it with narrow entries. |
connector_endpoint_allowlist_invalid | An allowlist entry is invalid; every connector call fails with 500. | Fix the entry named in the log. |
core-api or the scheduler does not start: ConnectorUnsafeDevOverrideRefused | The development override is on outside a development install or under stig. | Turn the override off. |