Files
vpd-permission-poc/docs/design/546-hermes-vm-deploy/README.md

114 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Redmine #546 - 외부 VM 배포 설계
## 현재 기준 배포 대상
이 문서의 최신 운영 기준은 아래와 같다. 과거 `hermes`/`130.162.134.59` 기록은 초기 개발·실험 배포 이력으로만 본다.
| 구분 | 값 |
| --- | --- |
| 개발·빌드 VM | `hermes` |
| 공개 서비스 배포 VM | `opc@161.33.6.45` (`vnic-aidp-poc`) |
| 공개 주소 | `https://kb.cloud-handson.com` |
| DNS | `kb.cloud-handson.com → 161.33.6.45` |
| VM 서비스 | `vpd-backoffice.service` |
| 앱 수신 주소 | `127.0.0.1:8080` |
| 공개 프록시 | Nginx `80/443 → 127.0.0.1:8080` |
| 인증서 | Lets Encrypt / Certbot Nginx plugin |
| 앱 디렉터리 | `/home/opc/apps/vpd-backoffice` |
| Wallet 디렉터리 | `/home/opc/apps/vpd-backoffice/wallet` |
반복 배포 시 완료 판정은 반드시 공개 주소 기준으로 한다.
```bash
curl -k -sS https://kb.cloud-handson.com/login
```
`hermes` 내부의 `8082` 응답만 확인하고 완료 처리하지 않는다. `8082`는 과거/개발 배포 경로에 해당할 수 있다.
## 프로젝트 개요
VPD Backoffice는 Oracle Database VPD/ORDS 기능을 백오피스 권한 테이블로 제어하는 Spring Boot 관리 도구다. 사용자는 Oracle DB schema user가 아니라 Bearer Token으로 식별되는 application user이며, 사용자/그룹/역할/권한/행 규칙/컬럼 NULL 처리 설정이 VPD policy function과 ORDS 조회 결과에 반영된다.
## 목표
외부 VM에 VPD Backoffice를 올려 상시 실행하고, 이후 개선 작업을 같은 방식으로 반복 배포할 수 있게 한다.
## 초기 확인 결과
- 초기 확인 시점에는 `~/.ssh/config``Host hermes` 항목이 잡히지 않아 `ssh hermes``Could not resolve hostname hermes`로 실패했다.
- 이후 `Host hermes``130.162.134.59`, `User opc`, `IdentityFile /Users/joungminko/devkit/credential/8-31.pem`로 확인됐다.
- 로컬 `.env``TNS_ADMIN=/Users/.../Wallet_D8AUKRO81636MON0`처럼 로컬 절대 경로를 사용하므로, VM 배포 시 wallet 디렉토리와 `TNS_ADMIN`을 원격 경로로 재작성해야 한다.
## 배포 방식
- 기본 개발/빌드 host는 `hermes`일 수 있으나, 공개 서비스 배포 대상은 `opc@161.33.6.45`다.
- 배포 스크립트의 기본값이 `hermes`인 경우, 운영 배포에서는 반드시 `--host` 또는 SSH alias가 `161.33.6.45`를 가리키는지 확인한다.
- 로컬에서 `mvn -DskipTests package`로 jar를 빌드한다.
- 원격 디렉토리 기본값은 `~/apps/vpd-backoffice`다.
- 배포 패키지 구성:
- Spring Boot executable jar
- VM용 `.env`
- ADB wallet 디렉토리
- `start.sh`, `stop.sh`, `status.sh`
- VM용 `.env`는 로컬 `.env`를 기반으로 하되 아래 값을 원격 경로 기준으로 덮어쓴다.
- `TNS_ADMIN`
- `BACKOFFICE_DB_URL`
- `BACKOFFICE_ORDS_DB_URL`
- `BACKOFFICE_PORT`
- 원격 프로세스는 systemd `vpd-backoffice.service`로 기동한다.
- `User=opc`, `Restart=on-failure`, `NoNewPrivileges=true`, `PrivateTmp=true`를 적용한다.
- 환경 파일은 `/etc/vpd-backoffice/vpd-backoffice.env`에 두고 `root:opc`, `640` 권한으로 제한한다.
- Wallet과 초기 관리자 자격증명 파일은 앱 디렉터리에 두고 각각 `700` 디렉터리와 `600` 파일 권한으로 제한한다.
## 완료 기준
- `scripts/deploy-backoffice-vm.sh`가 jar, `.env`, wallet, start/stop/status 스크립트를 원격에 설치할 수 있다.
- 대상 alias가 없으면 명확하게 실패한다.
- 배포 후 원격 `status.sh`와 HTTP `/login` 헬스체크가 가능하다.
- 현재 공개 운영에서는 Nginx 80/443만 외부에 열고, Spring Boot 애플리케이션 포트는 VM 내부 loopback으로 제한한다.
## 과거 hermes 배포 결과
- 배포 대상: `hermes` / `opc@130.162.134.59`
- 원격 경로: `/home/opc/apps/vpd-backoffice`
- Java runtime: `java-21-openjdk-headless`
- 기동 방식: `/home/opc/apps/vpd-backoffice/start.sh`
- PID 파일: `/home/opc/apps/vpd-backoffice/app.pid`
- 로그 파일: `/home/opc/apps/vpd-backoffice/app.log`
- VM firewalld: `8082/tcp` open
- OCI NSG: `218.39.170.82/32 -> tcp/8082` ingress 추가
- 외부 헬스체크: `http://130.162.134.59:8082/login` HTTP 200
## 2026-07-07 KBAIPOC VM 배포 결과
- 배포 대상: `opc@161.33.6.45` (`vnic-aidp-poc`), 서비스: `vpd-backoffice.service`.
- Java: Oracle Linux 9의 `java-21-openjdk-headless`를 설치했다.
- 앱은 Nginx 뒤의 `127.0.0.1:8080`에서만 수신한다.
- ADB Wallet은 앱 디렉터리의 `wallet/`에 배치하고, 앱은 `kbaipoc_high` 서비스 별칭으로 접속한다.
- 새로운 ADB에 표준 VPD POC 스키마, `CB_ORDS`, 백오피스 지원 객체, 동적 VPD 필터를 VM SQLcl로 초기화했다. 핵심 지원 테이블 5개와 `CB_AGENT_CTX_PKG`, `CB_AGENT_DOC_VPD_FILTER``VALID` 상태를 확인했다.
- 초기화 SQL은 현재 스키마의 `CB_PERMISSION_RULE` 5열 모델에 맞춰 seed 열을 명시하고, 지원 객체 생성은 재실행 가능하도록 `ORA-00955`를 처리한다. Autonomous Database의 parallel DML 충돌을 피하기 위해 보조 SQL은 parallel DML을 비활성화하고 seed 전 트랜잭션을 끝낸다.
- VM 내부 로그인과 인증된 대시보드에서 ADB 조회·도움말 SVG를 확인했다.
## 2026-07-07 HTTPS 전환 결과
- 공개 주소: `https://kb.cloud-handson.com`.
- DNS A 레코드 `kb.cloud-handson.com → 161.33.6.45`와 Nginx HTTP-01 경로를 외부에서 검증했다.
- Nginx는 80/443에서 수신하고 `127.0.0.1:8080`의 Spring Boot 서비스로 프록시한다. HTTP 요청은 HTTPS로 `301` 리다이렉트한다.
- Lets Encrypt 인증서를 Certbot Nginx 플러그인으로 발급했다. 인증서 CN은 `kb.cloud-handson.com`, 만료일은 2026-10-05다.
- `certbot-renew.timer`를 enable해 자동 갱신을 설정했다.
- SELinux enforcing 환경에서 `httpd_can_network_connect`를 영구 허용해 Nginx의 localhost upstream 연결을 허용했다.
- 백오피스 환경은 `BACKOFFICE_REQUIRE_HTTPS=true`, secure session cookie로 전환했다.
## 검증
- `mvn test`
- `scripts/deploy-backoffice-vm.sh --dry-run`
- 운영 배포 대상 SSH alias가 `opc@161.33.6.45`를 가리키는지 확인
- 운영 배포 대상의 `systemctl status vpd-backoffice` 확인
- 원격 내부 `/login` HTTP 200
- 외부 `/login` HTTP 200
- `systemctl status vpd-backoffice``active (running)`이고 앱 로그에서 `vpd-backoffice-pool` 연결이 성공한다.
- VM SQLcl에서 VPD context package body와 dynamic filter가 `VALID`이다.
- `https://kb.cloud-handson.com/login`이 외부에서 HTTP `200`을 반환하고 인증서 발급자가 Lets Encrypt인지 확인한다.
- `http://kb.cloud-handson.com/login`은 HTTPS 주소로 `301` 리다이렉트한다.