Skip to content

fix: CSP role API symmetry & registry sync fixes, CSP validation remediation guidance, security - #90

Merged
MZC-CSC merged 39 commits into
m-cmp:mainfrom
MZC-CSC:develop
Aug 10, 2026
Merged

MZC-CSC merged 39 commits into
m-cmp:mainfrom
MZC-CSC:develop

Conversation

@dogfootman

@dogfootman dogfootman commented Aug 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Added

  • CSP validation failure steps (AWS/GCP OIDC/SAML/WIF) now include structured remediation guidance (console steps, trust policy templates, docs links) instead of a bare failure message; GCP OIDC step 4/5 checks are now real STS/impersonation calls instead of placeholders (#149)
  • Symmetric per-type role update APIs: UpdatePlatformRole, UpdateWorkspaceRole, UpdateCspRoleMaster — RoleMaster update was previously missing entirely (create/delete-only) (#150)
  • CreateCspRoleMaster/DeleteCspRoleMaster — CSP-type RoleMaster create/delete, completing platform/workspace/csp symmetry (#155)
  • MC_IAM_MANAGER_PLATFORMADMIN_WORKSPACE_ROLE env var to explicitly pick the workspace role assigned to platformAdmin during clean install, instead of silently assuming PREDEFINED_ROLE's first entry (#160)

Fixed

  • updateCspRole mcmp API registry action pointed at an unregistered route; corrected across all three registry files (#148)
  • Registry sync no longer silently skipped: fixed _meta.generatedAt invalidation that prevented syncServicesAndActions from picking up registry YAML edits (#150)
  • Removed dead UpdateCspRole(RoleMaster) handler whose stale swagger comment was the source of the broken registry path above; renamed the real CSP-role-record update handler to UpdateCspRole for naming symmetry with createCspRole/deleteCspRole/getCspRoleById (#150)
  • UpdateCspRole was overwriting Name/Description with empty strings whenever the console (which treats Name as read-only) omitted them — fixed to only apply non-empty values, matching the existing guard on other fields (#151)
  • UpdateCspRole now also reflects IdpIdentifier/IamIdentifier/IamRoleId/Path (#147)
  • CreatePlatformRole built a RoleSub slice via append on top of a pre-sized make(), doubling the slice and writing half the rows with an empty RoleType; switched to indexed assignment matching CreateWorkspaceRole (#153)
  • FindRoleMasterCspRoleMappings/FindWorkspaceRoleCspRoleMappings hardcoded auth_method='OIDC', so SAML/SECRET_KEY-registered mappings never showed up in lookups; filter is now optional (#154)
  • CreateRole/UpdateRole always wrote CSP role mappings with authMethod=OIDC regardless of the request, silently converting SAML/SECRET_KEY mappings back to OIDC on every edit (#154)
  • DeleteCspRole (/roles/csp/id/:roleId) actually only removed the RoleMaster's RoleSub tag despite its name; it now deletes the real CSP role record (mapping cleanup, cascade, and cloud-side role deletion for AWS), matching CreateCspRole. The old RoleMaster delete/guard logic moved to the new DeleteCspRoleMaster (#155)
  • DeleteCspRoleRecord cascade tried to delete from CspRolePermission, a model never included in AutoMigrate — the table doesn't exist in any environment, so every delete failed with a 500. Removed the dead cleanup step (#156)
  • nginx ssl_ciphers only listed RSA-suite ciphers; an ECDSA (Let's Encrypt) certificate couldn't negotiate under TLS 1.2, breaking Alibaba IMS OIDC discovery. Added ECDSA suites (#157)
  • nginx returned a bare 400 (internal 497) when a plaintext HTTP request hit an SSL-only port (e.g. 3001, 9090) on IP/domain installs; added an error_page 497 redirect to HTTPS at the http context so it applies to every listen <port> ssl server block (#158)
  • ListUserProjectsByWorkspace returned 403 for platformAdmin whenever the caller had no mcmp_user_workspace_roles mapping (e.g. right after a clean install), because it lacked the platformAdmin bypass that ListUserWorkspaces already had — added the same bypass, plus an optional clean-install step to assign platformAdmin a default workspace role (#159, #160)
  • Removed legacy project-by-id actions from an unused mcmp_api.yaml asset (#146)

Migration notes

  • updateCspRole registry path fix requires a registry re-sync — now works correctly thanks to the _meta.generatedAt fix included in this range

yh-noh and others added 30 commits July 28, 2026 11:13
chore: remove legacy project-by-id actions from unused mcmp_api.yaml asset
fix: UpdateCspRole이 IdpIdentifier 등 4필드를 반영하도록 수정
updateCspRole이 PUT /api/roles/csp-roles/id/{roleId}를 가리켰으나
해당 PUT 라우트가 등록되어 있지 않았음. 실제 CSP Role 레코드 수정
핸들러(UpdateCspRoleRecord)가 등록된 경로 /api/roles/csp/id/{roleId}로
수정. 세 레지스트리 파일 모두 동일하게 반영.
fix: mcmp API 레지스트리 updateCspRole 액션이 미등록 라우트를 가리키던 문제 수정
CspValidationService의 각 ValidationStep에 실패 시 첨부할 구조화된
설정 방안(RemediationGuide: Summary/ConsoleSteps/Template/DocsRef)
필드를 추가. stepRunner가 remediation을 받아 실패 시 자동 첨부하도록
시그니처 변경. 기존 22개 호출부는 전부 nil로 갱신(동작 변화 없음) —
AWS/GCP별 실제 remediation 콘텐츠는 후속 브랜치에서 채운다.
AWS OIDC/SAML/SECRET_KEY 검증 실패 단계에 CSP 콘솔 조치 방법을 담은
RemediationGuide를 첨부한다. AWS/Keycloak 리소스를 확인하는 단계
(OIDC/SAML Provider, IAM Role Trust Policy, Keycloak 클라이언트 설정,
Access Key 등)에는 콘솔 경로와 Trust Policy 템플릿을 제공하고, DB
내부 조회 단계(매핑 조회, CspRole 설정)는 CSP 콘솔 조치가 없으므로
그대로 nil 유지.
… CSP validation

GCP OIDC 검증(validateGCPWithOIDC) step 4/5가 문자열만 반환하던 placeholder였던
문제(OI-17)를 해결. GcpCredentialService에 ExchangeToken/GenerateAccessToken을
독립 메서드로 노출하여 STS 토큰 교환과 SA Impersonation을 각각 검증하고,
실패 시 CSP 콘솔에서의 조치 방법(RemediationGuide)을 함께 반환하도록 확장.

- ExchangeTokenAndImpersonate는 두 신규 메서드를 내부에서 호출하도록 리팩터링
  (기존 호출부인 csp_credential_service.go의 동작/시그니처는 변경 없음)
- step 4(GCP STS 토큰 교환), step 5(SA Impersonation) 실패 시 WIF Pool/Provider,
  Service Account 설정 방법을 안내하는 RemediationGuide 첨부
- GCP STS/IAM Credentials 엔드포인트를 테스트에서 오버라이드 가능한 패키지
  변수로 분리하여 단위 테스트 추가
validateGCPWithOIDC의 Step 3/4도 credential-issuance 경로와 동일하게
Access Token을 GCP WIF STS에 전달하고 있었다. ID Token으로 수정.
… in remediation text

CspRole.idp_identifier가 GCP WIF STS audience로 그대로 전달되므로
//iam.googleapis.com/ 접두사가 필요하다는 점과, attributeCondition을
in 대신 등가 비교로 쓰는 것을 권장하는 안내를 gcpStsRemediation에 추가.
실 GCP 계정 검증 중 발견한 두 함정을 반영.
…remediation

실제 mcmp-admin/mcmp-operator SA로 WIF impersonation을 구성하며
roles/iam.workloadIdentityUser만으로는 토큰 발급(generateAccessToken)이
403(iam.serviceAccounts.getAccessToken denied)으로 실패함을 확인.
roles/iam.serviceAccountTokenCreator를 함께 부여해야 한다는 점을
gcpSaImpersonationRemediation 안내에 반영.
feat: add remediation guidance to CSP validation
레지스트리 YAML을 고쳐도 서비스의 _meta(version/generatedAt)를 갱신하지
않으면 syncServicesAndActions가 해당 서비스 액션 전체를 조용히 스킵한다
(shouldUpdateService). IAM-TECH-020의 updateCspRole 경로 수정이 배포+
수동 동기화 후에도 반영되지 않았던 원인. mc-iam-manager 서비스의
generatedAt을 갱신해 실제로 재동기화되도록 수정.

shouldUpdateService 단위테스트 3건 추가(동일 메타 스킵/generatedAt
변경 시 갱신/신규 서비스 항상 갱신).
레지스트리 updateCspRole 액션이 가리키던 미등록 라우트(/api/roles/csp-roles/id/{roleId})의
실체는 main.go에 등록된 적 없는 죽은 핸들러 UpdateCspRole(RoleMaster, roleType=csp)이었고,
그 swagger 주석이 registry에 잘못된 경로를 흘려보내고 있었다. 이 죽은 핸들러를 제거해
swagger 문서(docs/, src/docs/)에서도 잘못된 경로가 사라지도록 재생성했다.

CSP Role 레코드(mcmp_role_csp_roles) 수정 핸들러는 형제 액션(createCspRole/deleteCspRole/
getCspRoleById)과 이름을 맞춰 UpdateCspRoleRecord -> UpdateCspRole로 변경했다(경로는
기존과 동일 /api/roles/csp/id/{roleId}).

한편 RoleMaster(플랫폼/워크스페이스/CSP 공용 역할 정의) 수정은 platform-roles/workspace-roles
namespace에 Create/Delete/Get만 있고 Update가 빠져있던 것으로 확인되어, 대칭을 맞춰
UpdatePlatformRole/UpdateWorkspaceRole을 신설했다. CSP 타입 RoleMaster 수정은
UpdateCspRoleMaster(/api/roles/csp-roles/master/id/{roleId})로 명확히 분리해
CSP Role 레코드 수정(UpdateCspRole)과 이름이 겹치지 않게 했다.

RoleMaster에는 타입이 없고 RoleSub가 타입을 가지며(다중 가능) 하므로, 세 핸들러 모두
요청 바디의 RoleTypes가 아닌 DB의 기존 RoleSub를 기준으로(GetRoleByID) roleId가 실제로
해당 타입인지 검증하도록 가드를 구현했다. 관련 단위테스트 3건 추가.
fix: mcmp API 레지스트리 동기화 버그 수정 + CSP Role 관련 API 정리
.env contained real Keycloak/DB/CSP secrets and was tracked in git
despite being listed in .gitignore. Untrack it so it stops being
committed going forward; the file remains on disk for local runtime
config. All exposed values must be rotated separately.
콘솔 Edit 모달은 Name을 읽기 전용으로 취급해 저장 요청에 cspRoleName을
보내지 않는데, existingRole.Name = req.CspRoleName이 IdpIdentifier 등
다른 필드와 달리 빈 값 가드 없이 무조건 반영되어 저장할 때마다 Name이
빈 문자열로 초기화되고 있었다. Description도 동일 문제 확인, 같은
패턴(값 있을 때만 반영)으로 함께 수정.

단위 테스트 2건 추가(빈 이름으로 수정 시 기존 이름 보존 / 실제 이름
전달 시 정상 반영).
fix(security): stop tracking .env (IAM-BUG-009)
make()로 만든 zero-value 슬롯에 append로 덧붙이던 기존 로직이 실제로는
요청 개수의 2배 슬라이스를 만들었고, 앞쪽 절반이 RoleType="" 오염 row로
DB에 저장됐다. CreateWorkspaceRole과 동일한 인덱스 대입 패턴으로 통일.
FindRoleMasterCspRoleMappings가 auth_method='OIDC'로 고정 필터링해
SAML/SECRET_KEY로 등록된 매핑이 조회에서 항상 누락되던 문제를 옵셔널
필터(req.AuthMethod 지정 시에만 필터링)로 교체.

부수 발견: 같은 파일의 FindWorkspaceRoleCspRoleMappings에도 동일한
하드코딩이 있어 같은 패턴으로 함께 수정.
- DeleteCspRole(레코드 CRUD 네임스페이스, /roles/csp/id/:roleId)가 실제로는
  RoleMaster의 RoleSub 태그만 삭제하던 이름-동작 불일치를 해소. 이제 이 경로는
  실제로 CspRole(mcmp_role_csp_roles) 레코드를 삭제한다: 참조하는
  RoleMasterCspRoleMapping을 먼저 정리(DeleteRoleCspRoleMappingsByCspRoleID 신규)한
  뒤 레코드를 cascade 삭제(CspRolePolicyMapping/CspRolePermission 포함)하고,
  CspType=aws인 경우 실제 클라우드 Role도 함께 삭제한다(CreateCspRole과 대칭되는
  CspType 분기).
- 기존 RoleMaster/RoleSub 삭제 로직(Predefined 체크, 매핑 존재 시 차단 가드)은
  신설된 DeleteCspRoleMaster(DELETE /roles/csp-roles/master/id/:roleId)로 이전 —
  DeletePlatformRole/DeleteWorkspaceRole과 동일한 패턴.
- CreateCspRoleMaster(POST /roles/csp-roles/master) 신설 — CreatePlatformRole/
  CreateWorkspaceRole과 대칭되는 csp 타입 전용 생성 API. UpdateCspRoleMaster(PR #150
  머지 완료)에 이어 Create/Delete까지 platform/workspace/csp 3타입 API 대칭 완성.
- 죽은 코드였던 CspRoleService/CspRoleRepository의 기존 DeleteCspRole/DeleteCSPRole
  (하드삭제/존재하지 않는 테이블명 JOIN/cascade 미정리/CspType 무관 AWS 하드코딩의
  4중 버그)는 새 로직으로 완전히 대체.
- swagger 재생성(docs/, src/docs/ 양쪽)

Test plan: 단위테스트 7건 신규(레포지토리 cascade 1건, 핸들러 6건) — 전부 PASS
fix: UpdateCspRole이 빈 값 Name/Description을 무조건 덮어써 데이터 유실되는 버그 수정
…ub-bug

fix(role): CreatePlatformRole RoleSub 배열 생성 버그 수정
SAML CSP 확장(IAM-FIX-004) 완료로 실제 SAML 매핑이 쓰이기 시작하면서 발견:

- UpdateRole(role_handler.go)이 RoleMasterCspRoleMapping 재생성 시
  req.CspRoles의 authMethod를 무시하고 항상 constants.AuthMethodOIDC로
  고정 반영하고 있었음. 저장(수정) 때마다 기존 SAML/SECRET_KEY 매핑이
  OIDC로 덮어써지는 문제.
- CreateRole이 CSP 역할 생성 후 매핑 생성용 createdCspRoles를 재구성할 때
  원본 요청의 authMethod를 복사하지 않아, SAML로 생성한 CSP 역할인데도
  매핑은 항상 OIDC로 기록되던 문제.

두 곳 모두 요청에 지정된 authMethod를 그대로 전달하도록 수정(비어있으면
CreateRoleCspRoleMapping repository가 기존과 동일하게 OIDC로 기본 반영).

IAM-BUG-020(FindRoleMasterCspRoleMappings 등 OIDC 하드코딩 제거) 작업 중
사용자 확인으로 함께 발견되어 같은 PR에 포함.
…pings-oidc-hardcode

fix(role): CSP 역할 매핑 조회 auth_method OIDC 하드코딩 제거
fix(role): DeleteCspRole 재배선(레코드 삭제) + CSP 타입 Create/Delete API 대칭 완성
IAM-TECH-022에서 신설한 DeleteCspRoleRecord가 cascade 정리 대상으로
CspRolePermission(mcmp_csp_role_permissions)을 삭제 시도했으나, 이 모델은
main.go의 AutoMigrate 목록에 포함된 적이 없어 어떤 환경에도 테이블이
존재하지 않는다. 관련 레포지토리 메서드(AddPermissionsToCSPRole 등)도
호출부 없는 죽은 코드로 확인. 실제 원격 dev 환경에서 DELETE 호출 시
"relation does not exist" 500 에러로 항상 실패하던 것을 재현·수정.

CspRolePermission 삭제 단계를 제거하고, 실제 존재하는
CspRolePolicyMapping cascade 정리는 유지. 테스트 DB 마이그레이션에서도
CspRolePermission을 제거해 향후 동일 회귀를 테스트가 잡아낼 수 있도록 함.
…t-table

fix(role): DeleteCspRoleRecord api 보완
Ubuntu and others added 9 commits August 4, 2026 06:38
ssl_ciphers only listed RSA-suite ciphers (ECDHE-RSA-*), but the
server's Let's Encrypt certificate is ECDSA. No cipher could be
negotiated under TLS 1.2 for an ECDSA cert, causing handshake_failure
and breaking Alibaba IMS OIDC discovery (TLS 1.3-only backends work
by accident since TLS 1.3 cipher suites are cert-signature-agnostic).
fix(nginx): allow ECDSA cipher suites for TLS 1.2
IP/도메인으로 설치한 경우 3001, 9090 등 SSL 전용 포트로 평문 HTTP 요청이
들어오면 nginx가 내부적으로 497 코드를 발생시키고 400을 반환하던 문제.
http 컨텍스트에 error_page 497 리다이렉트를 한 줄 추가해 모든
listen <port> ssl 서버 블록에 상속되도록 처리.
ListUserWorkspaces는 platformAdmin이면 멤버십 검사를 건너뛰고 전체
workspace/project를 반환하지만, ListUserProjectsByWorkspace는 같은 우회
분기가 없어 mcmp_user_workspace_roles 매핑이 없으면 platformAdmin도
403을 받았다. 두 API가 동일한 platformAdmin 우회 패턴을 쓰도록 맞춘다.
1_setup_auto.sh에 Step 8-1을 추가해, 워크스페이스-프로젝트 매핑 이후
platformAdmin 계정에 기본 workspace의 workspace role(PREDEFINED_ROLE
첫 항목)을 할당한다. platformAdmin이라도 mcmp_user_workspace_roles
매핑이 없는 상태 자체를 줄이는 보완 조치이며, 실패해도 non-fatal로
처리해 클린 설치 전체를 막지 않는다.
…ject-scope

fix(user): platformAdmin의 workspace project 목록 조회 403 수정
fix(nginx): SSL 전용 포트에 평문 HTTP 요청 시 HTTPS로 리다이렉트
…per로 통일

IAM-BUG-022(#159) 수정에서 새로 넣은 platformAdmin 판별 루프가 이미
같은 파일에 있던 checkRoleFromContext와 중복이었다. 이런 중복이
바로 IAM-BUG-022 자체의 원인(ListUserWorkspaces에만 있던 우회 분기가
ListUserProjectsByWorkspace에 이식되지 않음)이었으므로, 기존
checkRoleFromContext(c, []string{"platformAdmin"})를 재사용하도록
정리해 같은 클래스의 버그가 재발할 여지를 줄인다.

또한 1_setup_auto.sh의 platformAdmin 기본 workspace role 할당이
PREDEFINED_ROLE 첫 항목을 암묵적으로 admin급으로 가정하던 부분에,
운영자가 순서를 바꾼 환경을 위해 MC_IAM_MANAGER_PLATFORMADMIN_WORKSPACE_ROLE
오버라이드를 추가한다.
refactor(user): I코드 리뷰 후속 정리
@MZC-CSC
MZC-CSC merged commit 2826b72 into m-cmp:main Aug 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants