Odchozi IP adresa portalu
Kdyz cizi sluzba odmitne pristup, prvni otazka je, z jake adresy se vlastne vola. Z containeru to videt neni, vidi to az protistrana, takze se zepta echo sluzby podle EGRESS_IP_URL a vysledek se drzi v pameti po EGRESS_IP_TTL_MS. Prazdna EGRESS_IP_URL funkci vypne, prepsat ji jde na vlastni echo pod svou domenou. Adresa je natvrdo na strance Konektory a u kazdeho odmitnuteho overeni v logu. Pripojuje se jen u 401 a 403 - jinde nema co rict a nestoji za volani ven. Neni to tajemstvi: kazda volana sluzba tuhle adresu stejne vidi. Endpoint egress-ip je registrovany pred GET /:id, jinak by ho router vzal jako id konektoru. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ab88979627
commit
4545de8076
@@ -2,6 +2,7 @@ import {
|
||||
AlertTriangle,
|
||||
CheckCircle2,
|
||||
Eye,
|
||||
Globe,
|
||||
Info,
|
||||
EyeOff,
|
||||
Pencil,
|
||||
@@ -28,6 +29,7 @@ import type {
|
||||
Connector,
|
||||
ConnectorCheck,
|
||||
ConnectorTestResult,
|
||||
EgressIp,
|
||||
Service,
|
||||
ServiceCredentialField,
|
||||
ServiceOverview,
|
||||
@@ -54,6 +56,11 @@ export default function Connectors() {
|
||||
const [services, setServices] = useState<ServiceOverview | null>(null);
|
||||
const [connectors, setConnectors] = useState<Connector[] | null>(null);
|
||||
const [storage, setStorage] = useState<StorageStatus | null>(null);
|
||||
/**
|
||||
* Adresa, ze ktere portal vola ven. Cizi sluzby maji seznamy povolenych IP
|
||||
* a bez teto informace se neda rict, jestli je na nich prave ta nase.
|
||||
*/
|
||||
const [egress, setEgress] = useState<EgressIp | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
@@ -83,6 +90,14 @@ export default function Connectors() {
|
||||
|
||||
useEffect(load, [load]);
|
||||
|
||||
// Zvlast a bez blokovani stranky: je to volani ven a kdyz nedobehne,
|
||||
// konektory se tim zdrzet nesmi.
|
||||
useEffect(() => {
|
||||
apiFetch<EgressIp>('/api/dashboard/connectors/egress-ip')
|
||||
.then(setEgress)
|
||||
.catch(() => setEgress(null));
|
||||
}, []);
|
||||
|
||||
const servicesById = useMemo(() => {
|
||||
// ServiceWithUsage, ne Service: karta ukazuje i vychozi adresu sluzby.
|
||||
const map = new Map<string, ServiceWithUsage>();
|
||||
@@ -128,6 +143,8 @@ export default function Connectors() {
|
||||
*/}
|
||||
{storage && storage.mode !== 'postgres' && <StorageNotice storage={storage} />}
|
||||
|
||||
{egress && <EgressNotice egress={egress} />}
|
||||
|
||||
<DataState loading={loading} error={error} onRetry={load}>
|
||||
{(connectors?.length ?? 0) === 0 ? (
|
||||
<p className="py-10 text-center text-sm text-white/45">
|
||||
@@ -203,6 +220,42 @@ function StorageNotice({ storage }: { storage: StorageStatus }) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ze ktere adresy portal vola ven.
|
||||
*
|
||||
* Duvod, proc to je na strance napevno a ne az u chyby: cizi sluzby maji
|
||||
* seznamy povolenych IP adres a z containeru neni videt, jak ho protistrana
|
||||
* vidi. Bez teto radky se pri odmitnutem pristupu hada, misto aby se porovnal
|
||||
* jeden retezec se seznamem.
|
||||
*/
|
||||
function EgressNotice({ egress }: { egress: EgressIp }) {
|
||||
return (
|
||||
<div className="glass mb-4 flex items-start gap-3 rounded-card p-4">
|
||||
<Globe className="mt-0.5 size-4 shrink-0 text-white/40" />
|
||||
<div className="min-w-0">
|
||||
{egress.ip ? (
|
||||
<>
|
||||
<p className="text-sm text-white/70">
|
||||
Volání odcházejí z IP <span className="font-mono text-white">{egress.ip}</span>
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-white/40">
|
||||
Tuhle adresu vidí volaná služba, takže právě ona musí být na jejím seznamu
|
||||
povolených. Zjištěno {formatDateTime(egress.checkedAt)} přes {egress.source}.
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-sm text-white/70">Odchozí IP adresu se nepodařilo zjistit.</p>
|
||||
<p className="mt-0.5 text-xs text-white/40">
|
||||
{egress.error ?? 'Bez důvodu.'} Adresu echo služby určuje EGRESS_IP_URL.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- mala karta
|
||||
|
||||
function ConnectorCard({
|
||||
@@ -422,6 +475,11 @@ function ConnectorLogs({
|
||||
<span className="text-white/70">{formatDateTime(check.at)}</span>
|
||||
{check.ok ? <Badge tone="ok">prošlo</Badge> : <Badge tone="danger">selhalo</Badge>}
|
||||
<span>Ověřeno: {check.checked}</span>
|
||||
{check.egressIp && (
|
||||
<span>
|
||||
voláno z IP <span className="font-mono text-white/60">{check.egressIp}</span>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{check.ok ? (
|
||||
|
||||
@@ -397,6 +397,8 @@ export interface ConnectorCheck {
|
||||
request: { method: string; path: string; url: string } | null;
|
||||
/** Vybrane hlavicky odpovedi. Rikaji, kdo odpoved vydal. */
|
||||
responseHeaders: Record<string, string> | null;
|
||||
/** Odchozi IP portalu ve chvili volani. Jen u odmitnuteho pristupu. */
|
||||
egressIp: string | null;
|
||||
}
|
||||
|
||||
export interface ConnectorTestResult {
|
||||
@@ -413,6 +415,20 @@ export interface ConnectorTestResult {
|
||||
baseUrl?: string;
|
||||
/** Vybrane hlavicky odpovedi. Rikaji, kdo odpoved vydal. */
|
||||
responseHeaders?: Record<string, string>;
|
||||
/** Odchozi IP portalu. Jen u odmitnuteho pristupu. */
|
||||
egressIp?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Odchozi IP adresa portalu.
|
||||
* Adresa, kterou vidi volana sluzba - tedy ta, ktera musi byt na seznamu
|
||||
* povolenych. Z containeru ji videt neni, zjistuje se echo sluzbou.
|
||||
*/
|
||||
export interface EgressIp {
|
||||
ip: string | null;
|
||||
source: string;
|
||||
checkedAt: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ServiceCatalog {
|
||||
|
||||
Reference in New Issue
Block a user