Przejdź do treści

MCP

Audyt Claude Code i serwerów MCP w środowiskach hostowanych samodzielnie

Autor Olivares AI 6 min do przeczytania

Zespół platformowy udostępnia Claude Code kilkunastu inżynierom. Aby był użyteczny, podpinają go do kilku serwerów MCP: jeden odczytuje monorepo, drugi odpytuje replikę raportową, trzeci zakłada zgłoszenia. W ciągu tygodnia agent czyta kod źródłowy, sięga do bazy danych i wywołuje wewnętrzne narzędzia — a nikt nie potrafi odpowiedzieć na pytanie, które prędzej czy później zada audytor: który agent zrobił co, na jakim zasobie i czy można udowodnić, że nie zostało to później zmienione?

To nie jest hipotetyczna luka. Niezależne badania branżowe (CSA/Token, n=418) wykazały, że około 82% organizacji ma uruchomione agenty AI, o których nie wie, podczas gdy zaledwie około 21% prowadzi ich inwentaryzację w czasie rzeczywistym. Claude Code i MCP to dokładnie ten rodzaj możliwości, który wdraża się szybko i wyprzedza historię audytową. Dobra wiadomość: możliwą do obrony ścieżkę audytu da się osiągnąć w całości wewnątrz własnego perymetru, bez opuszczania go przez jakiekolwiek dane czy sekrety.

Dlaczego oczywista konfiguracja nie przejdzie audytu

Typowe pierwsze wdrożenie współdzieli jedno poświadczenie. Każda instancja Claude Code uwierzytelnia się wobec warstwy MCP oraz wobec baz danych w dalszej części przepływu jako to samo konto usługowe — mcp-runner, ci-bot, coś generycznego. Działa to i po cichu niszczy atrybucję.

Gdy dziesięciu agentów działa jako jeden podmiot, dziennik audytu bazy danych pokazuje dziesięć zapisów od mcp-runner i nic więcej. Nie da się stwierdzić, sesja którego inżyniera wydała polecenie UPDATE, czy pochodziło ono z interaktywnego promptu Claude Code, czy z zadania bezobsługowego, ani które narzędzie MCP znajdowało się na ścieżce. Niezależne badania (Optro) szacują odsetek organizacji potrafiących prześledzić działanie agenta z powrotem do konkretnej osoby na około 28%. Współdzielone konto usługowe to jeden ze strukturalnych powodów, dla których atrybucja się załamuje: dziennik audytu potrafi pokazać, co się stało, ale nigdy — który agent to zrobił.

Drugą porażką jest integralność. Nawet zespoły, które logują per działanie, zwykle zapisują dane do magazynu modyfikowalnego. Jeśli dzienniki znajdują się w tym samym systemie, do którego może dotrzeć atakujący (lub wadliwy agent), to „mamy dzienniki” nie znaczy to samo co „mamy dowody”. Audytor wyraźnie rozróżnia te dwie rzeczy.

Tożsamość per agent jest fundamentem

Wszystko w dalszej części przepływu zależy od atrybucji, więc tożsamość trzeba naprawić w pierwszej kolejności. Zamiast jednego współdzielonego tokenu należy wydawać odrębną, krótkotrwałą tożsamość dla każdego agenta — najlepiej dla każdej sesji. Tożsamość podróżuje wraz z żądaniem do serwera MCP i do każdego zasobu, do którego sięga agent, dzięki czemu podmiotem zapisanym przy bazie danych jest agent, a nie generyczny runner.

To właśnie nadaje sens zasadzie least-privilege. Agenta raportowego można ograniczyć do dostępu wyłącznie do odczytu na replice raportowej; agent wydaniowy otrzymuje prawo zapisu tylko do artefaktów, których jest właścicielem. Teraz pojedynczy zaobserwowany zapis poza tą obwiednią staje się precyzyjnym, możliwym do przypisania sygnałem, a nie szumem na współdzielonym koncie. Wyrażona jako polityka, intencja jest dosadna:

agent "reporting-assistant" {
  # Claude Code session via the reporting MCP server
  resource "prod-postgres/reporting_replica" {
    access     = "read"      # SELECT only
    deny       = ["write", "ddl"]
  }
  resource "s3://billing-exports" {
    access = "read"
  }
  on_violation {
    action = "block_and_alert"   # refuse at access time, not just log
  }
}

Nie chodzi o składnię — chodzi o to, że polityka nazywa agenta, nazywa zasób i oddziela odczyt od odczytu/zapisu. To rozdzielenie jest całą istotą rzeczy.

Traktuj adnotacje MCP jako niezaufane sygnały

Narzędzia MCP mogą opisywać same siebie adnotacjami takimi jak readOnlyHint i destructiveHint. Są one naprawdę przydatne do triażu — narzędzie, które deklaruje się jako destrukcyjne, zasługuje na ściślejszą politykę. Specyfikacja MCP wprost stwierdza jednak, że są to wskazówki i klienci nie mogą polegać na nich przy decyzjach dotyczących bezpieczeństwa. Pochodzą one z serwera, czyli z tego samego elementu, który właśnie audytujesz. Narzędzie może zadeklarować readOnlyHint: true, a mimo to wykonać zapis — czy to wskutek błędu, błędnej konfiguracji, czy celowego obejścia.

Właściwą postawą jest zatem potwierdzanie, a nie zaufanie. Adnotację należy potraktować jako deklarację, a następnie skonfrontować ją z prawdą podstawową z warstwy, której narzędzie nie kontroluje:

  • Dzienniki audytu bazy danych (na przykład pgAudit dla PostgreSQL) mówią, czy SELECT lub UPDATE rzeczywiście został wykonany.
  • Span OpenTelemetry z serwera MCP i usług w dalszej części przepływu pokazują graf wywołań oraz przeprowadzone operacje.
  • Sygnały eBPF na poziomie jądra są zabezpieczeniem antyewazyjnym: wywołanie systemowe zapisu do pliku lub gniazda jest obserwowalne w jądrze niezależnie od tego, co narzędzie zadeklarowało w przestrzeni użytkownika.

Gdy adnotacja mówi „tylko do odczytu”, a jądro zaobserwowało zapis, ta sprzeczność jest głównym ustaleniem — narzędzie z readOnlyHint, które zapisało do prod-postgres, to dokładnie ten dryf względem zasady least-privilege, dla którego warto kogoś obudzić. Różnica między tym, na co polityka zezwoliła, a tym, co kolektory zaobserwowały, jest miejscem, w którym kryje się rzeczywiste ryzyko.

Rejestr, który audytor zaakceptuje

Ścieżka audytu jest dowodem tylko wtedy, gdy jest odporna na manipulacje. Każde zdarzenie należy zapisywać do rejestru z dopisywaniem tylko na końcu i łańcuchem skrótów (append-only, hash-chained): każdy rekord zawiera skrót poprzedniego, więc każda edycja lub usunięcie w dalszej części łańcucha go zrywa i jest wykrywalne. Każdy wiersz przypisuje działanie konkretnemu agentowi, nazywa zasób, rozróżnia odczyt i odczyt/zapis oraz niesie poziom pewności — attributed, gdy zarówno tożsamość, jak i wynik są potwierdzone, approximate, gdy coś trzeba było wywnioskować. Poziom pewności jest pokazywany uczciwie; przybliżone dopasowanie nigdy nie jest przedstawiane jako udowodnione.

ts=2026-06-08T09:14:02Z agent=reporting-assistant@s3f1 tool=sql-read     resource=prod-postgres/reporting_replica  op=R   outcome=allow   conf=attributed   prev=8a1c…
ts=2026-06-08T09:14:05Z agent=reporting-assistant@s3f1 tool=export-writer resource=s3://billing-exports          op=R   outcome=allow   conf=attributed   prev=2f90…
ts=2026-06-08T09:17:48Z agent=data-export-job@b22e     tool=sql-write     resource=prod-postgres/customers          op=RW  outcome=DENY    conf=attributed   prev=c7d3…  policy=read_only_violation

Ten trzeci wiersz to ten, na którym skupia się audytor: próba zapisu na tabeli, do której agent nie miał uprawnień zapisu, odrzucona w momencie dostępu, przypisana do nazwanego agenta i zakotwiczona w łańcuchu. Ponieważ polityka jest egzekwowana w chwili dostępu — a nie jedynie logowana po fakcie — odmowa jest mechanizmem kontrolnym, a nie analizą powykonawczą.

Dwie kolejne właściwości sprawiają, że ścieżka się broni. Uprzywilejowane wglądy same podlegają audytowi: spojrzenie na mapę dostępu jest zapisywane, więc na pytanie „kto co zobaczył” da się odpowiedzieć. Oraz eksport dowodów jest odporny na manipulacje — audytorowi przekazuje się podpisany wycinek łańcucha, który może niezależnie zweryfikować, zamiast pliku CSV, który musi przyjąć na wiarę.

WłaściwośćWspółdzielone konto usługoweTożsamość per agent + rejestr z łańcuchem skrótów
AtrybucjaJeden podmiot dla wszystkich agentówDziałanie powiązane z konkretnym agentem/sesją
Odczyt a zapisZlane w jednoRozróżnione i weryfikowane wobec polityki
IntegralnośćModyfikowalne dziennikiAppend-only, łańcuch zrywa się przy edycji
Eksport gotowy dla audytoraCSV przyjmowany na wiaręPodpisany, niezależnie weryfikowalny wycinek

Dlaczego self-hosted ma tutaj znaczenie

Wszystko to działa bez opuszczania Twojej sieci przez cokolwiek. Kolektor obserwuje — dzienniki, OpenTelemetry, eBPF jako zabezpieczenie na poziomie jądra — zamiast znajdować się na ścieżce danych agenta, więc jeśli zawiedzie, nigdy nie zepsuje agenta ani stojącego za nim żądania produkcyjnego. Rejestr przechowuje relacje dostępu, a nie dane: zapisuje, że reporting-assistant odczytał reporting_replica, a nie wiersze, które zostały zwrócone. Dane wejściowe, które mogą zawierać sekrety lub dane osobowe, są redagowane i skanowane pod kątem sekretów, zanim cokolwiek zostanie zapisane. Dla środowisk air-gapped, podlegających RODO lub ograniczeniom rezydencji danych jest to różnica między historią audytową, której można bronić, a taką, której obronić się nie da: nic na temat Twojego użycia Claude Code i MCP nie dzwoni do domu, ponieważ system w ogóle nie widzi danych.

Claude Code i MCP warto wdrażać. Potrzebują jedynie ścieżki audytu zbudowanej w taki sam sposób, w jaki zbudowano by ją dla dowolnej innej uprzywilejowanej automatyzacji — najpierw tożsamość, potwierdzone wyniki, zakotwiczone dowody. Aby zobaczyć, jak mapa dostępu i odporny na manipulacje rejestr łączą się ze sobą, model bezpieczeństwa oraz przegląd produktu wchodzą głębiej w każde z tych zagadnień.

Najczęstsze pytania

Czy mogę zaufać atrybutowi readOnlyHint narzędzia MCP jako dowodowi, że dana operacja była tylko do odczytu?

Nie. Specyfikacja MCP stwierdza, że adnotacje narzędzi, takie jak readOnlyHint i destructiveHint, są jedynie wskazówkami i muszą być traktowane jako niezaufane, ponieważ pochodzą z serwera, a nie z warstwy egzekwowania. Należy używać ich do triażu i sygnalizowania sprzeczności, ale rzeczywisty wynik odczytu/zapisu trzeba udowodnić za pomocą telemetrii lub sygnałów na poziomie jądra (span OpenTelemetry, dzienniki audytu bazy danych, eBPF). Zaufanie należy pokładać w potwierdzonym wyniku, a nie w adnotacji.

Jak przypisać działanie Claude Code do konkretnego agenta zamiast do współdzielonego konta usługowego?

Należy wydawać odrębną, krótkotrwałą tożsamość dla każdego agenta lub każdej sesji zamiast jednego współdzielonego tokenu. Gdy agent sięga do bazy danych lub serwera MCP, ta tożsamość podróżuje wraz z żądaniem, dzięki czemu rejestr audytu zapisuje, który agent co zrobił. Współdzielone konto usługowe zlewa wszystkich agentów w jeden podmiot i uniemożliwia zarówno zasadę least-privilege per agent, jak i odporną na manipulacje atrybucję po fakcie.

Sprawdź dostęp Twoich agentów

Olivares AI to otwarta platforma w modelu hostowanym samodzielnie dla całego środowiska AI w organizacji. Wdrożenie na własnej infrastrukturze zapewnia mapę dostępu, o którą od dawna proszą zespoły bezpieczeństwa i platformowe.