Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
33b0ac0
feat(cloud-env-001): credential/connection 화면 개발 방식 전환 (cb-spider → m…
yh-noh Apr 14, 2026
5382ae8
fix(cloud-env-001): credentialHolder API 미배포 대응 - connConfig에서 holder…
yh-noh Apr 14, 2026
8eaeae1
feat(cloud-env-001): listCloudOS → GetProviderList 교체 및 Provider Name…
yh-noh Apr 15, 2026
b8e7f6b
Merge branch 'develop' into feat-web-cloud-env-001
yh-noh Apr 15, 2026
44f7bb9
fix(cloud-env-001): api.yaml GetProviderList 중복 키 제거 (develop 머지 충돌)
yh-noh Apr 15, 2026
54faea1
merge(develop): develop 최신화 - MC_WEB_CONSOLE_ prefix 적용 및 충돌 해결
yh-noh May 26, 2026
f51f111
feat(cloud-env-001): 원격 백엔드 연결 설정 (mciam.onecloudcon.com HTTPS)
yh-noh May 26, 2026
fdebd5b
feat(cloud-env-001): 원격 Framework 서비스 URL 변경 (mciam.onecloudcon.com)
yh-noh May 26, 2026
278b8bd
fix(cloud-env-001): cb-tumblebug Credential 암호화 호환성 수정
yh-noh May 26, 2026
09a6f8c
feat(cloud-env-001): Credentials/Connections 화면 기능 개선
yh-noh May 26, 2026
5b5530a
Merge pull request #182 from MZC-CSC/feat-web-cloud-env-001
MZC-CSC May 26, 2026
020e592
fix: 역할 메뉴 권한 저장 후 사이드바 즉시 갱신
yh-noh May 29, 2026
e3079c4
fix(WEB-BUG-015, WEB-TECH-008): 조직 관련 메뉴 및 companyinfo 화면 추가
yh-noh May 29, 2026
c739966
Merge pull request #183 from MZC-CSC/fix-web-menu-org-issues
MZC-CSC May 29, 2026
760a784
feat(iam): Users 화면 API 등록 및 users_api.js 누락 함수 구현
dogfootman Jun 3, 2026
cb93a7a
fix(roles): load menus_api.js on roles page to enable sidebar refresh
yh-noh Jun 4, 2026
61e3622
Merge pull request #184 from MZC-CSC/fix-web-menu-role-sync
MZC-CSC Jun 4, 2026
5dbf583
feat: add assignGroupPlatformRole and getGroupPlatformRoles to mc-iam…
yh-noh Jun 5, 2026
74e8528
merge: resolve conflict in users_api.js — keep updateUser/deleteUser …
yh-noh Jun 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions api/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ type DatabaseConfig struct {

// MCIAMConfig MC-IAM 설정
type MCIAMConfig struct {
Use bool
TicketUse bool
Use bool
TicketUse bool
UseRegistryURL bool
}

// Load 설정 로드
Expand All @@ -82,8 +83,9 @@ func Load() (*Config, error) {
SSLMode: getEnv("MC_WEB_CONSOLE_POSTGRES_SSLMODE", "disable"),
},
MCIAM: MCIAMConfig{
Use: getEnv("MC_WEB_CONSOLE_USE_IAM", "false") == "true",
TicketUse: getEnv("MC_WEB_CONSOLE_USE_TICKET_VALID", "false") == "true",
Use: getEnv("MC_WEB_CONSOLE_USE_IAM", "false") == "true",
TicketUse: getEnv("MC_WEB_CONSOLE_USE_TICKET_VALID", "false") == "true",
UseRegistryURL: getEnv("MC_WEB_CONSOLE_USE_REGISTRY_URL", "true") == "true",
},
SetupYaml: SetupYamlConfig{
McWebconsoleMenuYaml: getEnv("MC_WEB_CONSOLE_MENUYAML", ""),
Expand Down
61 changes: 38 additions & 23 deletions api/internal/handler/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ func SubsystemAnyController(c echo.Context) error {
// ActionSpec: 캐시 우선 → 없으면 api.yaml ActionSpec
effectiveActionSpec := actionSpec
if cfg.RegistryCache != nil {
if dynamicURL := cfg.RegistryCache.GetBaseURL(subsystemName, operationId); dynamicURL != "" {
log.Printf("[RegistryCache] BaseURL override for %s: %s", subsystemName, dynamicURL)
effectiveBaseURL = dynamicURL
if cfg.MCIAM.UseRegistryURL {
if dynamicURL := cfg.RegistryCache.GetBaseURL(subsystemName, operationId); dynamicURL != "" {
log.Printf("[RegistryCache] BaseURL override for %s: %s", subsystemName, dynamicURL)
effectiveBaseURL = dynamicURL
}
}
if cachedSpec := cfg.RegistryCache.GetActionSpec(subsystemName, operationId); cachedSpec != nil {
effectiveActionSpec = cachedSpec
Expand Down Expand Up @@ -271,18 +273,30 @@ func encryptCredentialBody(plainBody []byte, baseURL string, service *config.Ser
return nil, fmt.Errorf("empty publicKey from mc-infra-manager")
}

// 2. RSA 공개키 파싱
// 2. RSA 공개키 파싱 (cb-tumblebug은 PKCS#1 형식 "BEGIN RSA PUBLIC KEY" 반환)
block, _ := pem.Decode([]byte(pkData.PublicKey))
if block == nil {
return nil, fmt.Errorf("failed to decode PEM publicKey")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse RSA publicKey: %w", err)
}
rsaPub, ok := pubInterface.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("publicKey is not RSA")
var rsaPub *rsa.PublicKey
switch block.Type {
case "RSA PUBLIC KEY":
// PKCS#1 형식
rsaPub, err = x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse PKCS1 RSA publicKey: %w", err)
}
default:
// PKIX/SPKI 형식 (BEGIN PUBLIC KEY)
pubInterface, pkixErr := x509.ParsePKIXPublicKey(block.Bytes)
if pkixErr != nil {
return nil, fmt.Errorf("parse PKIX RSA publicKey: %w", pkixErr)
}
var ok bool
rsaPub, ok = pubInterface.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("publicKey is not RSA")
}
}

// 3. 평문 요청 파싱
Expand All @@ -297,10 +311,10 @@ func encryptCredentialBody(plainBody []byte, baseURL string, service *config.Ser
return nil, fmt.Errorf("generate AES key: %w", err)
}

// 5. credentialKeyValueList[].value AES-256-GCM 암호화
// 5. credentialKeyValueList[].value AES-256-CBC 암호화 (cb-tumblebug 호환)
encryptedKVList := make([]credentialKV, len(plain.CredentialKeyValueList))
for i, kv := range plain.CredentialKeyValueList {
cipherText, err := aesGCMEncrypt(aesKey, []byte(kv.Value))
cipherText, err := aesCBCEncrypt(aesKey, []byte(kv.Value))
if err != nil {
return nil, fmt.Errorf("encrypt credential value [%s]: %w", kv.Key, err)
}
Expand All @@ -327,22 +341,23 @@ func encryptCredentialBody(plainBody []byte, baseURL string, service *config.Ser
return json.Marshal(encrypted)
}

// aesGCMEncrypt AES-256-GCM 암호화. 반환값: nonce(12B) + ciphertext
func aesGCMEncrypt(key, plaintext []byte) ([]byte, error) {
// aesCBCEncrypt AES-256-CBC 암호화 (cb-tumblebug 호환)
// 반환값: IV(16B) + ciphertext (PKCS7 패딩, 블록 배수)
func aesCBCEncrypt(key, plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
if _, err := rand.Read(nonce); err != nil {
blockSize := block.BlockSize()
padding := blockSize - len(plaintext)%blockSize
padded := append(plaintext, bytes.Repeat([]byte{byte(padding)}, padding)...)
iv := make([]byte, blockSize)
if _, err := rand.Read(iv); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
return ciphertext, nil
ciphertext := make([]byte, len(padded))
cipher.NewCBCEncrypter(block, iv).CryptBlocks(ciphertext, padded)
return append(iv, ciphertext...), nil
}

// buildAuthHeader api.yaml의 auth 타입에 따라 Authorization 헤더 값 반환
Expand Down
40 changes: 26 additions & 14 deletions conf/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
services:
mc-infra-connector:
version: 0.9.4
baseurl: http://spider_url:1024/spider
baseurl: http://mciam.onecloudcon.com:1024/spider
auth:
type: basic
username:
password:
mc-iam-manager:
version: 0.2.11
baseurl: http://mciam.onecloudcon.com:5006
baseurl: http://mciam.onecloudcon.com:5000
auth:
type: bearer
mc-infra-manager:
version: 0.12.9
baseurl: http://52.79.163.111:1323/tumblebug
baseurl: http://mciam.onecloudcon.com:1323/tumblebug
auth:
type: basic
username: default
Expand All @@ -28,39 +28,39 @@ services:
type: bearer
mc-observability:
version: main
baseurl: http://observability_url:18080
baseurl: http://mciam.onecloudcon.com:18080
auth:
mc-application-manager:
version: main
baseurl: http://localhost:18084
baseurl: http://mciam.onecloudcon.com:18084
auth:
mc-application-manager-fe:
version: main
baseurl: http://application_manager_fe_url:18084
baseurl: http://mciam.onecloudcon.com:18084
auth:
mc-workflow-manager:
version: main
baseurl: http://workflow_url:18083
baseurl: http://mciam.onecloudcon.com:18083
auth:
mc-workflow-manager-fe:
version: main
baseurl: http://workflow_manager_fe_url:18083
baseurl: http://mciam.onecloudcon.com:18083
auth:
mc-cost-optimizer:
version: main
baseurl: http://cost_optimizer_url:18082
baseurl: http://mciam.onecloudcon.com:18082
auth: null
mc-cost-optimizer-fe:
version: main
baseurl: http://cost_optimizer_fe_url:7780
baseurl: http://mciam.onecloudcon.com:7780
auth: null
mc-data-manager:
version: main:20240923
baseurl: http://localhost:3300
baseurl: http://mciam.onecloudcon.com:3300
auth:
mc-data-manager-fe:
version: main
baseurl: http://data_manager_fe_url:3300
baseurl: http://mciam.onecloudcon.com:3300
auth:
serviceActions:
mc-infra-connector:
Expand Down Expand Up @@ -879,11 +879,11 @@ serviceActions:
description: 해당 프레임워크 역할에 할당된 메뉴 리스트를 반환합니다.
Deleteuser:
method: delete
resourcePath: /api/user/id/{userid}
resourcePath: /api/users/id/{userId}
description: 사용자를 삭제합니다.
Updateuser:
method: put
resourcePath: /api/user/id/{userid}
resourcePath: /api/users/id/{userId}
description: 사용자 정보를 업데이트 합니다.
Createworkspace:
method: post
Expand Down Expand Up @@ -1058,6 +1058,10 @@ serviceActions:
method: post
resourcePath: /api/roles/assign/platform-role
description: Platform Role 할당
removePlatformRole:
method: delete
resourcePath: /api/roles/unassign/platform-role
description: 사용자에게서 Platform Role 제거
UpdateUserStatus:
method: post
resourcePath: /api/users/id/{userId}/status
Expand Down Expand Up @@ -1110,6 +1114,14 @@ serviceActions:
method: delete
resourcePath: /api/users/id/{userId}/organizations/{organizationId}
description: 사용자 그룹 제거
assignGroupPlatformRole:
method: post
resourcePath: /api/groups/id/{groupId}/platform-roles
description: 그룹에 Platform Role 할당
getGroupPlatformRoles:
method: get
resourcePath: /api/groups/id/{groupId}/platform-roles
description: 그룹의 Platform Role 목록 조회
listCspAccounts:
method: post
resourcePath: /api/csp-accounts/list
Expand Down
32 changes: 12 additions & 20 deletions conf/webconsole_menu_resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ menus:
priority: 2
menunumber: 1220

- id: groups
parentid: organizations
displayname: Groups
restype: menu
isaction: true
priority: 2
menunumber: 1225

- id: approvals
parentid: organizations
displayname: Approvals
Expand Down Expand Up @@ -88,37 +96,21 @@ menus:
priority: 2
menunumber: 1310

- id: regions
- id: credentials
parentid: cloudsps
displayname: Regions
displayname: Credentials
restype: menu
isaction: false
isaction: true
priority: 2
menunumber: 1320

- id: connections
parentid: cloudsps
displayname: Connections
restype: menu
isaction: false
priority: 2
menunumber: 1330

- id: clouddrivers
parentid: cloudsps
displayname: Cloud Drivers
restype: menu
isaction: true
priority: 2
menunumber: 1340

- id: credentials
parentid: cloudsps
displayname: Credentials
restype: menu
isaction: false
priority: 2
menunumber: 1350
menunumber: 1330

- id: cspaccounts
parentid: cloudsps
Expand Down
2 changes: 2 additions & 0 deletions front/actions/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

var FRONT_ADDR string
var FRONT_PORT string
var API_SCHEME string
var API_ADDR string
var API_PORT string
var SESSION_SECRET string
Expand All @@ -15,6 +16,7 @@ func init() {
// Get environment variables with defaults
FRONT_ADDR = getEnvOrDefault("MC_WEB_CONSOLE_FRONT_ADDR", "0.0.0.0")
FRONT_PORT = getEnvOrDefault("MC_WEB_CONSOLE_FRONT_PORT", "3001")
API_SCHEME = getEnvOrDefault("MC_WEB_CONSOLE_API_SCHEME", "http")
API_ADDR = getEnvOrDefault("MC_WEB_CONSOLE_API_ADDR", "localhost")
API_PORT = getEnvOrDefault("MC_WEB_CONSOLE_API_PORT", "3000")
SESSION_SECRET = getEnvOrDefault("MC_WEB_CONSOLE_SESSION_SECRET", "mc-web-console-secret-key")
Expand Down
2 changes: 1 addition & 1 deletion front/actions/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var proxy *httputil.ReverseProxy

func init() {
var err error
ApiBaseHost, err = url.Parse("http://" + API_ADDR + ":" + API_PORT)
ApiBaseHost, err = url.Parse(API_SCHEME + "://" + API_ADDR + ":" + API_PORT)
if err != nil {
panic(err)
}
Expand Down
Loading
Loading