ops #460: add SQLcl environment check runbook
This commit is contained in:
82
docs/design/460-sqlcl-runbook-env-check/README.md
Normal file
82
docs/design/460-sqlcl-runbook-env-check/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# 설계서: SQLcl 기반 배포/롤백 런북 및 환경 점검 명령 정리 (#460)
|
||||
|
||||
> **상태**: Approved
|
||||
> **작성**: [AI] Architect · **최종수정**: 2026-06-25
|
||||
> **추적성** — Redmine: #460 · 관련 ADR: 없음
|
||||
> · 구현 파일: `scripts/check-sqlcl-backoffice-env.sh`, `docs/runbooks/460-sqlcl-vpd-deploy-runbook.md`, `run.sh` · 테스트: `./run.sh backoffice-env-check`
|
||||
|
||||
## 1. 목적 (Why)
|
||||
|
||||
운영자가 신규 DB/ORDS 환경에서 SQLcl, JDK, ADB 접속, ORDS endpoint를 적용 전에 점검하고 VPD filter 배포/검증/롤백 순서를 확인할 수 있게 한다.
|
||||
|
||||
## 2. 범위 (Scope)
|
||||
|
||||
- **포함**: SQLcl/JDK/DB/ORDS 환경 점검 스크립트, 배포/검증/롤백 런북, `run.sh backoffice-env-check` 명령.
|
||||
- **제외**: SQLcl 설치 자동화, JDK 설치 자동화, ORDS metadata 자동 생성.
|
||||
|
||||
## 3. 인수조건 (Acceptance Criteria)
|
||||
|
||||
- [ ] SQLcl 실행 파일과 버전을 확인한다.
|
||||
- [ ] Java 버전을 확인한다.
|
||||
- [ ] DB 접속 사용자와 `CB_AGENT_DOC_VPD_FILTER` 상태를 확인한다.
|
||||
- [ ] ORDS base URL과 documents endpoint의 HTTP 상태를 확인한다.
|
||||
- [ ] 운영자가 실행할 배포/검증/롤백 순서가 문서화된다.
|
||||
|
||||
## 4. 컨텍스트 & 제약
|
||||
|
||||
- `.env`는 민감 정보를 포함하므로 점검 출력에 password/token을 출력하지 않는다.
|
||||
- SQLcl 경로는 `SQLCL_BIN` 우선, 없으면 PATH의 `sql`을 사용한다.
|
||||
- JDK는 `SQLCL_JAVA_HOME`이 있으면 `JAVA_HOME`으로 사용한다.
|
||||
|
||||
## 5. 아키텍처 개요
|
||||
|
||||
```
|
||||
run.sh backoffice-env-check
|
||||
-> scripts/check-sqlcl-backoffice-env.sh
|
||||
-> SQLcl version
|
||||
-> Java version
|
||||
-> SELECT USER, function status
|
||||
-> curl ORDS endpoint
|
||||
```
|
||||
|
||||
## 6. 데이터 모델
|
||||
|
||||
- 입력 환경변수: `SQLCL_BIN`, `SQLCL_JAVA_HOME`, `BACKOFFICE_DB_USERNAME`, `BACKOFFICE_DB_PASSWORD`, `ADB_TNS`, `BACKOFFICE_ORDS_BASE_URL`.
|
||||
- 출력: PASS/FAIL 로그, 민감값 마스킹.
|
||||
|
||||
## 7. 함수 명세 (Function Specs)
|
||||
|
||||
| 함수 | 책임(1줄) | 시그니처(잠정) | 입력 | 출력 | 에러/실패 | 복잡? |
|
||||
|------|-----------|----------------|------|------|-----------|-------|
|
||||
| `resolve_sqlcl` | SQLcl 실행 파일 찾기 | bash function | env/path | path | 없으면 exit 1 | 단순 |
|
||||
| `check_db` | DB 접속과 function 상태 확인 | bash function | SQLcl connection | PASS/FAIL | SQLcl exit code | 단순 |
|
||||
| `check_ords` | ORDS endpoint HTTP 상태 확인 | bash function | base url/path | PASS/WARN | curl status | 단순 |
|
||||
|
||||
## 8. 흐름 / 알고리즘
|
||||
|
||||
1. `.env`를 로드한다.
|
||||
2. SQLcl 경로와 Java 버전을 출력한다.
|
||||
3. DB 접속 필수값 존재 여부를 확인한다.
|
||||
4. SQLcl로 현재 사용자와 VPD function 상태를 조회한다.
|
||||
5. ORDS endpoint에 GET을 보내 상태 코드를 확인한다.
|
||||
6. 다음 실행 명령을 안내한다.
|
||||
|
||||
## 9. 엣지케이스 & 에러 처리
|
||||
|
||||
- SQLcl 없음: `SQLCL_BIN=/path/to/sql` 안내.
|
||||
- DB 접속 실패: DB 설정 확인 메시지.
|
||||
- ORDS 404: base URL/path 확인 경고.
|
||||
- ORDS 401/403: endpoint는 살아 있으나 인증 필요 상태로 안내.
|
||||
|
||||
## 10. 테스트 계획
|
||||
|
||||
- `SQLCL_BIN=/tmp/sqlcl/sqlcl/bin/sql SQLCL_JAVA_HOME=... ./run.sh backoffice-env-check`
|
||||
|
||||
## 11. 리스크 & 대안 검토
|
||||
|
||||
- 선택: bash 점검 스크립트. 운영자가 Java/Maven 없이도 SQLcl/curl만으로 확인 가능하다.
|
||||
- 대안: Spring Boot health endpoint. 앱이 뜨기 전 문제를 잡기 어렵다.
|
||||
|
||||
## 12. 미해결 질문 (Open Questions)
|
||||
|
||||
- SQLcl을 repo 외부 어디에 표준 설치할지는 사용자 로컬/운영 환경 정책에 따른다.
|
||||
78
docs/runbooks/460-sqlcl-vpd-deploy-runbook.md
Normal file
78
docs/runbooks/460-sqlcl-vpd-deploy-runbook.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# SQLcl VPD 배포/검증/롤백 런북 (#460)
|
||||
|
||||
## 사전 점검
|
||||
|
||||
```bash
|
||||
SQLCL_BIN=/path/to/sql \
|
||||
SQLCL_JAVA_HOME=/path/to/jdk \
|
||||
./run.sh backoffice-env-check
|
||||
```
|
||||
|
||||
확인 항목:
|
||||
|
||||
- SQLcl 버전이 출력된다.
|
||||
- Java 11 이상이 출력된다.
|
||||
- DB 현재 사용자가 의도한 schema다. 예: `ADMIN`.
|
||||
- `CB_AGENT_DOC_VPD_FILTER` 상태가 `VALID`다.
|
||||
- ORDS endpoint가 200/401/403 중 하나를 반환한다. 404면 base URL 또는 path가 맞지 않는다.
|
||||
|
||||
## VPD filter 배포
|
||||
|
||||
```bash
|
||||
SQLCL_BIN=/path/to/sql SQLCL_JAVA_HOME=/path/to/jdk "$SQLCL_BIN" "USER/PASSWORD@TNS"
|
||||
```
|
||||
|
||||
SQLcl 안에서 실행:
|
||||
|
||||
```sql
|
||||
@sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql
|
||||
SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter
|
||||
@sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql
|
||||
```
|
||||
|
||||
기대 결과:
|
||||
|
||||
- function compile 성공
|
||||
- `SHOW ERRORS` 결과 없음
|
||||
- `Dynamic VPD filter unit checks passed`
|
||||
|
||||
## ORDS 회귀 검증
|
||||
|
||||
```bash
|
||||
SQLCL_BIN=/path/to/sql \
|
||||
SQLCL_JAVA_HOME=/path/to/jdk \
|
||||
./run.sh backoffice-vpd-ords-test
|
||||
```
|
||||
|
||||
기대 결과:
|
||||
|
||||
- HR: 3행, `DOC_ID=[1,2,6]`, `CONTENTS` 미노출
|
||||
- SELF: 1행, `DOC_ID=[3]`, `CONTENTS` 미노출
|
||||
- ALL: 6행, `DOC_ID=[1,2,3,4,5,6]`, `CONTENTS` 노출
|
||||
- INVALID_TOKEN: HTTP 403 등 성공이 아닌 응답
|
||||
|
||||
## 장애 시 확인 순서
|
||||
|
||||
1. `./run.sh backoffice-env-check`로 SQLcl/JDK/DB/ORDS 상태를 먼저 확인한다.
|
||||
2. DB function이 `INVALID`면 `SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter`를 본다.
|
||||
3. ORDS가 404면 `BACKOFFICE_ORDS_BASE_URL`과 `cb_protected_object.ords_path`를 비교한다.
|
||||
4. ORDS가 403이면 token hash, 만료시각, revoke 여부를 확인한다.
|
||||
5. 행 수가 맞지 않으면 `cb_user_role`, `cb_permission`, `cb_permission_rule`을 확인한다.
|
||||
|
||||
## 롤백
|
||||
|
||||
가장 단순한 롤백은 직전 Git revision의 `26_agent_ords_security_dynamic_vpd_filter.sql`을 다시 적용하는 것이다.
|
||||
|
||||
```bash
|
||||
git show HEAD~1:sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql > /tmp/previous-vpd-filter.sql
|
||||
SQLCL_BIN=/path/to/sql SQLCL_JAVA_HOME=/path/to/jdk "$SQLCL_BIN" "USER/PASSWORD@TNS"
|
||||
```
|
||||
|
||||
SQLcl 안에서:
|
||||
|
||||
```sql
|
||||
@/tmp/previous-vpd-filter.sql
|
||||
SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter
|
||||
```
|
||||
|
||||
롤백 후에도 반드시 ORDS 회귀 검증을 다시 실행한다.
|
||||
10
run.sh
10
run.sh
@@ -10,6 +10,7 @@
|
||||
# ./run.sh tests # 4-user (my/pg/both/none) 로 접속해서 행 필터 검증
|
||||
# ./run.sh audit # admin 으로 정책/뷰/유저 상태 점검
|
||||
# ./run.sh backoffice-support # Spring Boot 백오피스 보조 객체 생성
|
||||
# ./run.sh backoffice-env-check # SQLcl/JDK/DB/ORDS 환경 점검
|
||||
# ./run.sh backoffice-vpd-ords-test # SQLcl + ORDS VPD/Redaction 회귀 테스트
|
||||
# ./run.sh all # source → adb → tests → audit
|
||||
# ./run.sh teardown # ADB 측 객체 + 원격 link/cred 만 정리 (원격 PG/MySQL 데이터는 보존)
|
||||
@@ -181,6 +182,12 @@ do_backoffice_vpd_ords_test() {
|
||||
ok "backoffice-vpd-ords-test 완료"
|
||||
}
|
||||
|
||||
do_backoffice_env_check() {
|
||||
log "=== backoffice-env-check: SQLcl/JDK/DB/ORDS 환경 점검 ==="
|
||||
bash "$ROOT/scripts/check-sqlcl-backoffice-env.sh"
|
||||
ok "backoffice-env-check 완료"
|
||||
}
|
||||
|
||||
do_teardown() {
|
||||
log "=== teardown: ADB 측 객체 + dblink/credential 정리 ==="
|
||||
warn "원격 PG/MySQL 의 customers 테이블은 건드리지 않습니다 (수동으로 DROP 하세요)"
|
||||
@@ -233,6 +240,7 @@ case "$CMD" in
|
||||
tests) do_prereq; do_tests ;;
|
||||
audit) do_prereq; do_audit ;;
|
||||
backoffice-support) do_prereq; do_backoffice_support ;;
|
||||
backoffice-env-check) do_backoffice_env_check ;;
|
||||
backoffice-vpd-ords-test) do_backoffice_vpd_ords_test ;;
|
||||
teardown) do_prereq; do_teardown ;;
|
||||
all)
|
||||
@@ -253,6 +261,6 @@ case "$CMD" in
|
||||
ok "=== DDS DONE — Deep Data Security 변형 셋업 + 검증 통과 ==="
|
||||
;;
|
||||
*)
|
||||
die "알 수 없는 명령: $CMD (사용: prereq|source|adb|tests|audit|backoffice-support|backoffice-vpd-ords-test|all|teardown | dds|dds-setup|dds-tests|dds-teardown)"
|
||||
die "알 수 없는 명령: $CMD (사용: prereq|source|adb|tests|audit|backoffice-support|backoffice-env-check|backoffice-vpd-ords-test|all|teardown | dds|dds-setup|dds-tests|dds-teardown)"
|
||||
;;
|
||||
esac
|
||||
|
||||
82
scripts/check-sqlcl-backoffice-env.sh
Normal file
82
scripts/check-sqlcl-backoffice-env.sh
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env bash
|
||||
# Check SQLcl/JDK/ADB/ORDS prerequisites for the VPD backoffice scripts.
|
||||
set -Eeuo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
if [[ -f "$ROOT/.env" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
set -a; . "$ROOT/.env"; set +a
|
||||
fi
|
||||
|
||||
SQLCL_BIN="${SQLCL_BIN:-}"
|
||||
if [[ -z "$SQLCL_BIN" ]]; then
|
||||
SQLCL_BIN="$(command -v sql || true)"
|
||||
fi
|
||||
|
||||
if [[ -n "${SQLCL_JAVA_HOME:-}" ]]; then
|
||||
export JAVA_HOME="$SQLCL_JAVA_HOME"
|
||||
fi
|
||||
|
||||
DB_USER="${BACKOFFICE_DB_USERNAME:-${ADB_USER:-}}"
|
||||
DB_PASSWORD="${BACKOFFICE_DB_PASSWORD:-${ADB_PASSWORD:-}}"
|
||||
DB_TNS="${ADB_TNS:-}"
|
||||
ORDS_BASE="${BACKOFFICE_ORDS_BASE_URL:-https://yh0olybn5pqce4n-d8aukro81636mon0.adb.ap-seoul-1.oraclecloudapps.com/ords}"
|
||||
ORDS_PATH="${BACKOFFICE_REGRESSION_ORDS_PATH:-cb-ords/cb-agent-security/vpd/documents}"
|
||||
|
||||
fail() {
|
||||
echo "[FAIL] $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo "[WARN] $*" >&2
|
||||
}
|
||||
|
||||
pass() {
|
||||
echo "[PASS] $*"
|
||||
}
|
||||
|
||||
[[ -n "$SQLCL_BIN" && -x "$SQLCL_BIN" ]] || fail "SQLcl을 찾을 수 없습니다. SQLCL_BIN=/path/to/sql 로 지정하세요."
|
||||
[[ -n "$DB_USER" ]] || fail "BACKOFFICE_DB_USERNAME 또는 ADB_USER가 필요합니다."
|
||||
[[ -n "$DB_PASSWORD" ]] || fail "BACKOFFICE_DB_PASSWORD 또는 ADB_PASSWORD가 필요합니다."
|
||||
[[ -n "$DB_TNS" ]] || fail "ADB_TNS가 필요합니다."
|
||||
|
||||
echo "[INFO] SQLcl path: $SQLCL_BIN"
|
||||
"$SQLCL_BIN" -version
|
||||
|
||||
if command -v java >/dev/null 2>&1; then
|
||||
java -version 2>&1 | sed -n '1,3p'
|
||||
else
|
||||
warn "java 명령을 PATH에서 찾을 수 없습니다. SQLcl이 자체 Java를 쓰지 않는 환경이면 실패할 수 있습니다."
|
||||
fi
|
||||
|
||||
echo "[INFO] DB user: $DB_USER"
|
||||
{
|
||||
printf "%s\n" "WHENEVER SQLERROR EXIT SQL.SQLCODE"
|
||||
printf "%s\n" "SET SQLFORMAT ansiconsole"
|
||||
printf "%s\n" "SELECT USER AS current_user FROM dual;"
|
||||
printf "%s\n" "SELECT object_name, status FROM user_objects WHERE object_name = 'CB_AGENT_DOC_VPD_FILTER';"
|
||||
printf "%s\n" "exit"
|
||||
} | "$SQLCL_BIN" -s "$DB_USER/$DB_PASSWORD@$DB_TNS"
|
||||
pass "DB 접속 및 VPD function 상태 조회 완료"
|
||||
|
||||
ORDS_URL="${ORDS_BASE%/}/${ORDS_PATH}?limit=1"
|
||||
STATUS="$(curl -sS -o /tmp/vpd-backoffice-env-check-ords.json -w "%{http_code}" \
|
||||
-X POST "$ORDS_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{}" || true)"
|
||||
case "$STATUS" in
|
||||
200|401|403)
|
||||
pass "ORDS endpoint 응답 확인: HTTP $STATUS"
|
||||
;;
|
||||
404)
|
||||
warn "ORDS endpoint가 404입니다. BACKOFFICE_ORDS_BASE_URL과 ORDS path를 확인하세요: $ORDS_URL"
|
||||
;;
|
||||
*)
|
||||
warn "ORDS endpoint 응답이 예상 밖입니다: HTTP $STATUS ($ORDS_URL)"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "[INFO] 다음 검증: ./run.sh backoffice-vpd-ords-test"
|
||||
Reference in New Issue
Block a user