Skip to content

[Security][Connector] 연결 테스트 인증·egress·오류 비노출 강화 #392

Description

@HyungminYoon1

배경

POST /api/v1/connectors/test는 DB/SSH credential을 저장하지 않더라도 outbound network와 credential을 소비한다. 인증·조직 격리·분산 admission·strict egress·오류 비노출을 함께 적용해야 한다.

기존 구현은 public PostgreSQL과 TLS verify-full을 강제했지만 local/Docker용 포트만 추가하고 private/loopback 주소와 local PostgreSQL TLS 신뢰 경로를 제공하지 않았다. 따라서 일반 테스트는 가능해도 로컬·Docker UI에서 실제 Connector 연결 성공을 시연할 수 없는 계약 불일치가 있었다.

범위

보안 경계

  • 로그인 사용자와 active Organization membership을 요구한다.
  • Organization/user/network rate limit과 global/Organization/user bounded concurrency를 Redis에서 원자적으로 적용한다.
  • DNS 결과, private/link-local/metadata/reserved 주소, port와 실제 연결 peer를 검증하고 검증 IP에 연결을 고정한다.
  • timeout, bounded executor/lease, request ingress cap을 적용한다.
  • raw adapter/provider 예외, host/database/username/credential/driver detail을 응답·audit·log에 남기지 않는다.
  • SSH test는 approved host-key/private-network 정책 전까지 network 전에 거부한다.

Local/Docker 시연 경계

  • 일반 플랫폼 DB와 분리된 explicit connector-demo PostgreSQL/Redis profile을 제공한다.
  • CA signing key, server key와 generated credential은 runtime private named volume에만 둔다.
  • 공개 CA certificate만 git-ignore된 local/connector-test-tls/<mode>/로 export해 Gateway에 read-only로 제공한다.
  • local/development에서만 배포자가 지정한 최대 4개의 exact canonical hostname+port와 전용 CA file을 함께 허용한다.
  • wildcard, suffix, CIDR, raw IP target, request-controlled allowlist와 broad private-network 허용은 금지한다.
  • 허용된 local target도 모든 DNS 결과 검증, validated IP pinning, TLS verify-full, read-only SELECT 1과 one-attempt 제한을 유지한다.
  • localhost의 IPv4/IPv6 loopback을 모두 검증한 뒤 host publish와 일치하는 IPv4를 결정적으로 pin하고 fallback retry는 하지 않는다.
  • host published PostgreSQL/Redis port는 127.0.0.1에만 bind한다.
  • Docker-internal allowlist는 5432, host-run profile은 5432,55432로 최소화한다.
  • Compose 시작은 certificate-init 완료와 Redis/PostgreSQL health를 기다린다.
  • production에서 local target 또는 local CA override가 설정되면 Gateway startup을 실패시킨다.

완료 조건

  • 비인증·조직 범위 밖 요청은 body/admission/DNS/network 전에 차단된다.
  • private/metadata target과 우회 표현은 기본적으로 adapter 전에 차단된다.
  • local profile에서는 정확히 지정한 demo target만 성공하고 같은 private network의 다른 target과 임의 port는 차단된다.
  • local TLS PostgreSQL은 hostname 검증을 포함한 verify-full로 성공하며 plaintext·verify=false fallback이 없다.
  • production configuration은 local/private target 예외를 허용하지 않고 잘못된 설정에서 fail-fast한다.
  • 실제 Redis에서 마지막 rate/concurrency slot race, owner-safe release와 TTL recovery가 검증된다.
  • 실제 TLS PostgreSQL과 Redis를 사용한 host API와 Docker service-name smoke가 성공한다.
  • 관리 UI에서 인증 사용자와 active Organization으로 연결 테스트 성공을 한 번 확인한다.
  • 오류 응답과 로그에 credential 및 connection detail이 없다.
  • docs/features/connectors/, architecture와 ADR이 구현과 일치한다.
  • 최신 dev rebase, 단일 ADR 번호, targeted test와 PR 직전 전체 회귀 1회가 통과한다.

구현 상태

최신 origin/dev @ 977d37f0e379 기준이며 PR #467 HEAD는 8e08624d9b다.

  • Auth/organization, Redis admission, strict egress, local/Docker TLS demo, 오류 비노출과 실제 Redis/TLS/UI smoke는 구현·검증됐다.
  • Local pre-reservation, ASGI query sanitizer, CORS cooldown, typed detail adapter와 Redis-down integration fake 보완 뒤 PR Quality Gate가 통과했다.
  • 추가 Codex review의 production base Compose admission HMAC passthrough와 Nginx trailing-slash secret-ingress 누락을 보완했다.
  • Runtime/Compose/Helm 및 Nginx/ASGI를 함께 검사하는 Connector 통합 deployment contract를 도입했다.
  • 공식 문서와 local/mba-246 구현·결정·테스트 계획을 갱신했다.
  • 관련 architecture/composition/middleware 86건, Ruff, development/production Compose render와 Nginx syntax 검증이 통과했다.
  • PR-final 전체 회귀는 기존 계획대로 이미 1회 수행했으므로 이번 보완에서는 반복하지 않았다.
  • Push 직전 최신 origin/dev 기준 뒤처짐이 없음을 확인하고 feature/mba-246에 push했다.
  • PR #467의 Alembic, Gateway/root, Client, Shared, Workflow, Log, Sandbox, Python lint, Trusted CI와 최종 ci-required가 모두 통과했다. PostgreSQL contract job은 변경 범위 selector에 따라 정상 skip됐다.

병합 차단 조건

다음 중 하나라도 남으면 병합하지 않는다.

  • local/Docker에서 실제 성공 가능한 TLS Connector target이 없음
  • local 예외가 exact target이 아니라 broad private-network/CIDR 허용으로 구현됨
  • host demo port가 loopback 밖에 publish됨
  • production에서 local target/CA override를 startup 단계에서 거부하지 않음
  • 실제 Redis integration test가 없고 fake만 사용함
  • 실제 TLS PostgreSQL API/Docker smoke 또는 수동 UI smoke가 수행되지 않음
  • secret, credential 원문, 인증서 개인키 또는 raw connection payload가 저장소·로그·fixture에 포함됨
  • 공식 문서와 구현의 target/TLS/port 계약이 불일치함
  • Base Docker Compose가 외부 CONNECTOR_TEST_ADMISSION_HMAC_KEY 이름을 Gateway 컨테이너에 전달하지 않음
  • Nginx와 ASGI sanitizer가 canonical Connector test path와 단일 trailing slash를 동일하게 보호하지 않음
  • Runtime/Compose/Helm 및 Nginx/ASGI 통합 deployment contract 자동 검증이 통과하지 않음
  • PR 직전 전체 회귀가 통과하지 않음

비범위

Metadata

Metadata

Assignees

Type

No type

Fields

Priority

None yet

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions