개요 — 무엇을 하나
프로젝트는 팀이 운영하는 각 프로젝트의 메타데이터를 한곳에 모아 공유하는 레지스트리입니다. 소스 저장소(GitHub 등), CI/CD 파이프라인(Jenkins), 이 프로젝트가 사용하는 웹 서비스·데이터베이스, 백업 대상, 그리고 보호해야 할 기밀 정보의 위치를 등록해 "이 프로젝트가 무엇으로 구성되고, 어디에 배포되며, 무슨 비밀이 어디에 있는지"를 작업자 누구나 빠르게 파악하도록 합니다.
이 화면은 배포 도구가 아닙니다. 실제 빌드·배포는 Jenkins 에서 이뤄집니다. InfraGuard 는 여기서 파이프라인을 트리거하지 않으며, 등록된 정보는 정보 공유용 문서입니다. 저장한 URL·Job 이름·브랜치는 참조 링크·라벨일 뿐 실행되지 않습니다.
핵심 설계 원칙:
- 기밀 값은 절대 인라인 저장하지 않습니다. 비밀번호·토큰·키의 실제 값은 여기에 저장되지 않습니다. 대신 (1) Inventory 금고(
infr_vault_key)의 키를 참조하거나, (2) "무슨 비밀이 어디에 있는지"만 적는 마스킹 체크리스트로 기록합니다. - 모든 항목은 모달 하나의 탭 구조(개요·소스·CI/CD·연결·백업·기밀)로 편집합니다.
- 생성·수정·삭제와 금고 값 열람은 모두 감사 로그(
infr_audit_log)에 남습니다.
언제 쓰나
- 새 팀원이 합류해 "이 프로젝트 저장소·배포 URL·DB가 뭔지" 빠르게 안내가 필요할 때.
- 프로젝트별 web/db 종속성을 한눈에 정리해 장애 대응 시 영향 범위를 즉시 파악하고 싶을 때.
- 프로젝트가 의존하는 비밀들의 위치 지도(어떤 키가 어디에, 어느 금고 항목이 이 프로젝트용인지)를 문서화할 때.
- 백업 대상·주기를 프로젝트 메타로 명시해 백업 정책과 연결하고 싶을 때.
화면 구성
KPI 스트립
| 셀 | 의미 |
|---|---|
| 프로젝트 | 등록된 전체 프로젝트 수 |
| 외부 접근 | accessible=1 (외부 URL 이 있는) 프로젝트 수 |
| 내부 | accessible=0 (외부 노출 없는 내부 전용) 프로젝트 수 |
| 보관 | status=archived 프로젝트 수 |
프로젝트 카드
카드마다 다음이 표시됩니다:
- 아이콘·이름 — 외부 접근 프로젝트는
mdi-web, 내부 전용은mdi-folder-lock-outline. - URL 링크 —
accessible이고 URL 이 있으면 새 탭 열기 링크, 아니면내부배지. - 상태 배지 — 활성 / 중지 / 보관.
- 요약 한 줄.
- 구성 칩 — 등록된 요소만 칩으로 요약: 소스 · Jenkins · 환경 N · Web N · DB N · 백업 N · 기밀 N.
- 그룹 라벨(카테고리) + 편집·삭제 버튼(쓰기 권한 시).
편집 모달 (탭 6개)
.infr-modal__panel--wide 넓은 모달, 탭으로 영역을 나눕니다.
| 탭 | 입력 항목 |
|---|---|
| 개요 | 이름(필수) · 키(slug) · 상태 · 그룹 · 외부 접근 토글 · URL · 요약 · 태그 |
| 소스 | 저장소 제공자(GitHub/GitLab/Gitea/Bitbucket/기타) · 저장소 URL · 기본 브랜치 · 공개 범위(공개/비공개/내부) |
| CI/CD | Jenkins URL + 환경 리피터(dev/staging/prod 별 배포 URL·브랜치·Jenkins Job·메모) |
| 연결 | Web 서비스 체크박스(등록된 infr_web_service) + DB(수집기) 체크박스(access=database 수집기) |
| 백업 | 백업 대상 리피터(유형·대상·주기·메모) |
| 기밀 | 금고 키 참조(체크 + 값 열람) + 기밀 체크리스트 리피터(항목·위치·참조·메모) |
사용법
프로젝트 등록
- 우측 상단 [프로젝트 추가] 클릭(쓰기 권한 필요).
- 개요 탭에서 이름(필수)을 입력합니다. 키(slug)는 선택이며
^[a-z0-9_-]+$형식만 허용됩니다(예:coin-market). - 외부 접근이 가능한 서비스면 외부 접근 가능 토글을 켜고 URL 을 입력합니다. 내부 전용이면 토글을 끄면 URL 필드가 비활성화됩니다.
- 나머지 탭(소스·CI/CD·연결·백업·기밀)을 필요한 만큼 채웁니다. 모든 탭은 선택 사항입니다.
- [저장] — 서버가 검증 후
infr_project에 upsert 하고 카드를 갱신합니다.
CI/CD 환경 등록
CI/CD 탭에서 Jenkins URL 을 넣고 [환경 추가] 로 배포 대상을 행 단위로 추가합니다:
{
"env": "prod",
"url": "https://coin.example.com",
"branch": "main",
"jenkins_job": "coin_market-deploy-prod",
"note": "blue/green"
}
env는dev/staging/prod화이트리스트만 허용(그 외 값은 서버가dev로 강제).- 각 문자열 필드는 길이 제한(URL 255 · 브랜치 120 · Job 191 · 메모 255)으로 클램프됩니다.
- 환경은 최대 20개.
web/db 연결
연결 탭에서 이 프로젝트가 사용하는 자원을 체크로 연결합니다.
- Web 서비스 — Service ▸ Web 에 등록된
infr_web_service목록(이름·도메인)에서 선택. 저장은 web_service id 배열. - DB(수집기) — access=database 로 등록된 수집기(Admin ▸ Collectors / Service ▸ Database)의 key 배열.
각각 최대 50개까지 연결됩니다.
백업 대상 명시
백업 탭의 리피터에 이 프로젝트의 백업 정책을 문서화합니다(유형·대상·주기·메모). 이는 참조 메타이며 실행되지 않습니다 — 실제 백업 작업은 백업 스케줄 보드에서 관리합니다.
기밀 정보 관리 (핵심)
기밀은 두 방식을 함께 씁니다. 어느 쪽도 실제 비밀 값을 infr_project 에 저장하지 않습니다.
1) 금고 키 참조 (vault_key_ids)
- 기밀 탭에서 Inventory 금고(Assets ▸ Inventory ▸ Keys,
infr_vault_key)의 키를 체크해 연결합니다. - 목록은 마스킹 상태(id·카테고리·제목·사용자명만, 값 없음)로 내려옵니다.
- 연결된 키의 [값 열람] 을 누르면
POST /service/projects/vault-reveal이 그 순간에만 값을 복호화해 반환합니다.
금고 값 열람은 감사됩니다. 매 열람마다
infr_audit_log에vault_key.reveal(target=vault_key, via=project) 이 기록됩니다. 값은 화면에 잠깐 표시되고 클릭하면 클립보드로 복사됩니다 — 필요한 순간에만 열람하세요. 저장된 프로젝트 레코드에는 키 id 참조만 들어 있습니다.
2) 기밀 체크리스트 (secrets, 마스킹)
금고에 넣지 않은(또는 외부에 있는) 비밀은 위치만 기록합니다. 값은 절대 저장하지 않습니다.
| 필드 | 예시 |
|---|---|
label |
STRIPE_SECRET_KEY |
location |
.env (prod 서버 /var/www) |
ref |
1Password › Coin › prod |
note |
분기마다 회전 |
서버는 cleanList() 로 허용 키(label/location/ref/note)만 남기고 각 값을 255자로 클램프합니다. 네 필드가 모두 비면 그 행은 버려집니다.
삭제
편집 모달 좌하단 또는 카드의 [삭제] 로 제거합니다. 확인 후 POST /service/projects/delete → infr_project 행 삭제 + project.delete 감사.
데이터 소스
| 데이터 | 출처 |
|---|---|
| 프로젝트 레코드 | infr_project (마이그레이션 000715) |
| 그룹(카테고리) | infr_asset_group (group_id 참조) |
| Web 서비스 옵션 | infr_web_service (이름·도메인) |
| DB(수집기) 옵션 | infr_collector where access=database (key·title·host_alias) |
| 금고 키 옵션 | infr_vault_key — 마스킹(id·category·title·username, 값 없음) |
| 금고 값 열람 | infr_vault_key.revealSecret() (열람 시에만 복호화) |
| 감사 로그 | infr_audit_log (project.create/update/delete, vault_key.reveal) |
저장 스키마 (infr_project 발췌)
key varchar(60) unique nullable # slug
group_id int → infr_asset_group
name varchar(160) # 필수
status enum(active,paused,archived)
accessible boolean default 1
url varchar(255) # accessible=1 이면 노출
summary text
repo_provider enum(github,gitlab,gitea,bitbucket,other)
repo_url / default_branch / visibility(public,private,internal)
jenkins_url varchar(255)
environments json [{env,url,branch,jenkins_job,note}]
web_refs json → infr_web_service id 배열
db_refs json → infr_collector(database) key 배열
backup_targets json [{kind,target,schedule,note}]
vault_key_ids json → infr_vault_key id 배열 (값은 금고)
secrets json [{label,location,ref,note}] # 값 미저장 체크리스트
tags / meta json
이 화면은 라이브 폴링을 하지 않습니다. 저장·삭제·새로고침 버튼 시에만 목록을 다시 불러옵니다(
GET /service/projects/list). 실시간 상태가 필요한 것은 Service ▸ Catalog·Service ▸ Web 이 담당합니다.
권한
| 작업 | 라우트 | 최소 레벨 |
|---|---|---|
| 조회(index/list) | GET /service/projects, /list |
1 (demo, infr.auth) |
| 금고 값 열람 | POST /service/projects/vault-reveal |
1 (+ 감사) |
| 저장(생성/수정) | POST /service/projects/save |
2 (staff) |
| 삭제 | POST /service/projects/delete |
2 (staff) |
- 쓰기 게이트는 세션
infr_user_level >= 2(canWrite())로 검사합니다. 실패 시403+project.err.forbidden. vault_key_ids는 저장 시 실재하는 vault key id 만 통과시킵니다(InfrVaultKey::whereIn(...)존재 검증). 위조된 id 는 조용히 걸러집니다.- 레벨은 demo=1 · staff=5 · admin=10 기준이며, 일부 영역은
infr.level:N미들웨어로 별도 게이팅됩니다.
문제해결 · FAQ
Q. 저장 버튼을 눌러도 403 이 납니다. 쓰기는 레벨 2 이상만 가능합니다. viewer(레벨 1) 계정은 조회·금고 열람만 됩니다. 관리자에게 레벨 상향을 요청하세요.
Q. 금고 [값 열람] 이 비어 있게 나옵니다.
해당 금고 항목에 저장된 비밀이 없거나(hasSecret=false), 복호화에 실패한 경우입니다(APP_KEY 변경 등). Inventory ▸ Keys 에서 값을 다시 설정하세요. revealSecret() 은 실패 시 null 을 반환합니다.
Q. Web/DB 연결 목록에 아무것도 안 보입니다. Web 은 Service ▸ Web 에 웹 서비스가, DB 는 access=database 수집기가 먼저 등록돼 있어야 목록에 나타납니다. 등록 후 프로젝트 모달을 다시 열면 옵션이 채워집니다.
Q. 키(slug)를 저장하면 "형식 오류" 가 납니다.
키는 소문자·숫자·하이픈·언더스코어만 허용됩니다(^[a-z0-9_-]+$, 최대 60자). 공백·대문자·기타 기호는 제거하세요. 키는 선택 항목이므로 비워도 됩니다.
Q. 여기서 배포를 트리거할 수 있나요? 아니요. 배포는 Jenkins 에서 수행합니다. 이 화면은 Jenkins URL·Job 이름을 문서로만 보관합니다.
Q. 비밀 값을 그냥 secrets 메모에 적으면 안 되나요?
금물입니다. secrets 는 값을 저장하지 않는 위치 지도입니다. 실제 값은 Inventory ▸ Keys 금고(암호화 저장)에 넣고 vault_key_ids 로 참조하세요.
관련 항목
- Service ▸ Web —
web_refs로 연결하는 웹 서비스 대시보드. - Service ▸ Database —
db_refs로 연결하는 DB 수집기. - Service ▸ Catalog — 인스턴스별 데몬 서비스 라이브니스(라이브 상태는 여기).
- 백업 스케줄 보드 — 실제 백업 작업 정의·실행.
- Assets ▸ Inventory — 금고 키(
infr_vault_key)의 원본 관리 화면. - 감사 로그 — project.create/update/delete, vault_key.reveal 기록 확인.
