포털 사이트 링크에 SSO 자동로그인 적용 (Coder/Gitea OIDC 시작 URL + 뱃지)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,11 @@ SESSION_SECRET=change-me-to-a-long-random-string
|
|||||||
|
|
||||||
# --- DB (OpenEverest appdb, portal schema 전용 role) ---
|
# --- DB (OpenEverest appdb, portal schema 전용 role) ---
|
||||||
# host 는 클러스터 내부 OpenEverest pgbouncer (워크스페이스/Kubero 양쪽 도달).
|
# host 는 클러스터 내부 OpenEverest pgbouncer (워크스페이스/Kubero 양쪽 도달).
|
||||||
DATABASE_URL=postgresql://portal_app:7e2950ce6ed0c5a1457ea5b5@postgresql-6ox-pgbouncer.everest.svc.cluster.local:5432/appdb?options=-c%20search_path%3Dportal
|
# 주의: pgbouncer 가 SSL 필수 → sslmode=require. node pg 최신은 require 를 verify-full 로 취급하므로
|
||||||
|
# 자체서명 인증서 통과를 위해 uselibpqcompat=true 동반 필요.
|
||||||
|
# search_path 는 portal_app role 기본값(ALTER ROLE ... SET search_path=portal)으로 고정돼 있어
|
||||||
|
# URL 의 options 파라미터는 불필요(pgbouncer 가 startup options 거부함).
|
||||||
|
DATABASE_URL=postgresql://portal_app:7e2950ce6ed0c5a1457ea5b5@postgresql-6ox-pgbouncer.everest.svc:5432/appdb?uselibpqcompat=true&sslmode=require
|
||||||
|
|
||||||
# --- Keycloak OIDC (realm bokdev, client portal) ---
|
# --- Keycloak OIDC (realm bokdev, client portal) ---
|
||||||
OIDC_ISSUER=https://keycloak.bokdev.in/realms/bokdev
|
OIDC_ISSUER=https://keycloak.bokdev.in/realms/bokdev
|
||||||
|
|||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# AI DEV 포털 이미지. Kubero buildpack(node22 + npm install + node index.js)과 동일 구성.
|
||||||
|
# Kubero v3.1.1 buildpack 빌드잡이 harbor 단일세그먼트 경로로 push 실패하는 이슈 우회용:
|
||||||
|
# 이 이미지를 harbor.bokdev.in/kubero/ai-dev-portal-portal:main 으로 직접 push 하면
|
||||||
|
# Kubero 가 만든 web 파드가 그대로 pull 한다.
|
||||||
|
FROM node:22-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV PORT=8080
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["node", "index.js"]
|
||||||
26
deploy/portal-route.yaml
Normal file
26
deploy/portal-route.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# portal.bokdev.in → Kubero 가 배포한 portal Service.
|
||||||
|
# Kubero 파이프라인 ai-dev, production phase → ns ai-dev-production.
|
||||||
|
# Service 이름=portal-kuberoapp, port=80.
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: portal-route
|
||||||
|
namespace: ai-dev-production
|
||||||
|
spec:
|
||||||
|
hostnames:
|
||||||
|
- portal.bokdev.in
|
||||||
|
parentRefs:
|
||||||
|
- group: gateway.networking.k8s.io
|
||||||
|
kind: Gateway
|
||||||
|
name: bokdev-gateway
|
||||||
|
namespace: istio-ingress
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- group: ""
|
||||||
|
kind: Service
|
||||||
|
name: portal-kuberoapp
|
||||||
|
port: 80
|
||||||
@@ -82,6 +82,7 @@ a:hover { text-decoration: underline; }
|
|||||||
.site-card .ico { font-size: 22px; line-height: 1; }
|
.site-card .ico { font-size: 22px; line-height: 1; }
|
||||||
.site-card .name { font-weight: 600; color: var(--fg); }
|
.site-card .name { font-weight: 600; color: var(--fg); }
|
||||||
.site-card .desc { color: var(--fg-muted); font-size: 12px; }
|
.site-card .desc { color: var(--fg-muted); font-size: 12px; }
|
||||||
|
.sso-badge { display: inline-block; font-size: 10px; font-weight: 600; color: #1a7f37; background: #dafbe1; border: 1px solid #aceebb; border-radius: 999px; padding: 1px 7px; vertical-align: middle; margin-left: 4px; }
|
||||||
.group-title { font-size: 13px; font-weight: 600; color: var(--fg-muted); margin: 20px 0 8px; text-transform: uppercase; letter-spacing: .04em; }
|
.group-title { font-size: 13px; font-weight: 600; color: var(--fg-muted); margin: 20px 0 8px; text-transform: uppercase; letter-spacing: .04em; }
|
||||||
|
|
||||||
/* 버튼 */
|
/* 버튼 */
|
||||||
|
|||||||
11
src/sites.js
11
src/sites.js
@@ -1,11 +1,18 @@
|
|||||||
// 포털에 모아둘 사이트 카탈로그. 카테고리: 개발 핵심 / AI·데이터.
|
// 포털에 모아둘 사이트 카탈로그. 카테고리: 개발 핵심 / AI·데이터.
|
||||||
// icon 은 이모지(추가 의존성 없이 GitHub 감성 카드에 표시).
|
// icon 은 이모지(추가 의존성 없이 GitHub 감성 카드에 표시).
|
||||||
|
//
|
||||||
|
// url: 각 앱의 'OIDC 로그인 바로 시작' 엔드포인트를 쓰면, Keycloak SSO 세션이 있을 때
|
||||||
|
// 로그인 폼 없이 즉시 통과(자동 로그인)된다. 포털도 같은 Keycloak realm 으로 로그인하므로
|
||||||
|
// 포털 로그인 후 이 링크를 누르면 바로 들어간다.
|
||||||
|
// - Coder: /api/v2/users/oidc/callback (code 없으면 keycloak authorize 로 307)
|
||||||
|
// - Gitea: /user/oauth2/keycloak (auth source 명=keycloak, 307 로 keycloak authorize)
|
||||||
|
// SSO 미지원(Kubero=oauth2 미완성, Harbor 등)은 기본 URL 유지.
|
||||||
export const siteGroups = [
|
export const siteGroups = [
|
||||||
{
|
{
|
||||||
group: "개발 핵심",
|
group: "개발 핵심",
|
||||||
sites: [
|
sites: [
|
||||||
{ name: "Coder", url: "https://coder.bokdev.in", icon: "💻", desc: "웹 개발 워크스페이스 (VS Code + AI CLI)" },
|
{ name: "Coder", url: "https://coder.bokdev.in/api/v2/users/oidc/callback", icon: "💻", desc: "웹 개발 워크스페이스 (VS Code + AI CLI)", sso: true },
|
||||||
{ name: "Gitea", url: "https://gitea.bokdev.in", icon: "🍵", desc: "사내 Git 저장소" },
|
{ name: "Gitea", url: "https://gitea.bokdev.in/user/oauth2/keycloak", icon: "🍵", desc: "사내 Git 저장소", sso: true },
|
||||||
{ name: "Kubero", url: "https://kubero.bokdev.in", icon: "🚀", desc: "앱 배포 PaaS (*.apps.bokdev.in)" },
|
{ name: "Kubero", url: "https://kubero.bokdev.in", icon: "🚀", desc: "앱 배포 PaaS (*.apps.bokdev.in)" },
|
||||||
{ name: "Harbor", url: "https://harbor.bokdev.in", icon: "📦", desc: "컨테이너 이미지 레지스트리" },
|
{ name: "Harbor", url: "https://harbor.bokdev.in", icon: "📦", desc: "컨테이너 이미지 레지스트리" },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<a class="site-card" href="<%= s.url %>" target="_blank" rel="noopener">
|
<a class="site-card" href="<%= s.url %>" target="_blank" rel="noopener">
|
||||||
<span class="ico"><%= s.icon %></span>
|
<span class="ico"><%= s.icon %></span>
|
||||||
<span>
|
<span>
|
||||||
<span class="name"><%= s.name %></span><br/>
|
<span class="name"><%= s.name %><% if (s.sso) { %> <span class="sso-badge">SSO 자동로그인</span><% } %></span><br/>
|
||||||
<span class="desc"><%= s.desc %></span>
|
<span class="desc"><%= s.desc %></span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user