Skip to content

cd - #19

Merged
Sehi55 merged 3 commits into
mainfrom
dev
May 16, 2026
Merged

cd#19
Sehi55 merged 3 commits into
mainfrom
dev

Conversation

@Sehi55

@Sehi55 Sehi55 commented May 16, 2026

Copy link
Copy Markdown
Contributor

📝 작업 내용

이번 PR에서 작업한 내용을 설명해주세요.

  • cd

🚀 주요 변경 사항

완료한 이슈 번호
Close #14
관련된 이슈 번호 (닫고 싶지 않은 경우)
Related to #

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 프로덕션 자동 배포 워크플로우가 추가되었습니다.
    • 헬스 체크 및 정보 엔드포인트에 공개 접근이 허용되었습니다.
  • Chores

    • CI/CD 파이프라인 설정이 강화되었습니다.
    • 프로덕션 환경 설정이 추가되었습니다.
    • 내부 서비스 구성이 정규화되었습니다.

Review Change Stack

Sehi55 added 3 commits May 17, 2026 04:11
* feat: actuator 의존성 추가

* feat: ci-prod 구현
* Feat/14 prod settings (#15) (#16)

* feat: actuator 의존성 추가

* feat: ci-prod 구현

* feat: cd-prod 구현
* Feat/14 prod settings (#15) (#16)

* feat: actuator 의존성 추가

* feat: ci-prod 구현

* feat: cd-prod 구현

* fix: api 권한문제 때문에 헬스체크 실패 오류
@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

이 PR은 프로덕션 배포 자동화를 구현한다. CI-PROD 워크플로우가 main 브랜치의 코드를 테스트하고 ECR에 이미지를 푸시하며, CD-PROD 워크플로우가 ECS로 배포한다. 프로덕션 설정, Actuator 모니터링, 서비스 디스커버리 URI 정규화가 함께 추가된다.

Changes

Production CI/CD 파이프라인

Layer / File(s) Summary
CI-PROD 워크플로우: 빌드 및 이미지 푸시
.github/workflows/ci-prod.yml
main 브랜치의 pull_request/push 이벤트에서 Gradle 테스트를 실행하고, push 시에만 ECR에 Docker 이미지를 빌드하여 푸시한다. OIDC 기반 AWS 인증으로 ECR 접근을 수행한다.
CD-PROD 워크플로우: ECS 배포 자동화
.github/workflows/cd-prod.yml
CI-PROD 완료 또는 수동 트리거 시 ECR 이미지를 검증하고, ECS 태스크 정의를 jq로 렌더링(컨테이너 이미지 및 환경변수 주입)한 뒤 등록하고, 서비스를 강제 배포하며 안정화될 때까지 대기한다.
프로덕션 환경 설정 및 Actuator 지원
src/main/resources/application-prod.yml, build.gradle, src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java
application-prod.yml에 서버 포트, Eureka 설정, 네트워크 인터페이스 필터링, 관리 엔드포인트 노출을 추가하고, Actuator 의존성을 추가하며, /actuator/health와 /actuator/info 경로를 인증 없이 허용한다.
서비스 디스커버리 URI 정규화
src/main/resources/application.yml
spring.cloud.gateway 라우트의 서비스 discovery URI를 대문자(예: lb://USER-SERVICE)에서 소문자(예: lb://user-service)로 정규화한다.
CI 트리거 브랜치 정리
.github/workflows/ci.yml
pull_request 트리거에서 main 브랜치를 제거하고 dev만 유지하여, main 빌드를 ci-prod.yml으로 이관한다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • githyj-jang
  • qldo
  • Jinyoung-Kim96

Poem

🐰 프로덕션 배포의 꿈을 펼친다,
CI가 빌드하고 CD가 날린다,
Eureka와 Actuator로 건강을 확인하고,
자동화의 토끼굴로 빠져드는 우리,
한 번의 커밋으로 배포까지! 🚀

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR 제목 'cd'는 너무 모호하고 구체적이지 않아 변경사항의 주요 내용을 명확히 전달하지 못함. 제목을 'Add production configuration and CD pipeline' 또는 'Implement prod config and CD workflow' 등으로 변경하여 주요 변경사항을 명확히 표현하기 바람.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed PR은 이슈 #14의 모든 요구사항을 충족함: application-prod 설정 추가, CD 로직 구현, CI 파이프라인 추가, 보안 설정 업데이트 등.
Out of Scope Changes check ✅ Passed 모든 변경사항이 이슈 #14의 프로덕션 설정 및 CD 로직 추가 요구사항과 관련성이 있으며 범위 내 변경임.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Sehi55
Sehi55 merged commit 372fdeb into main May 16, 2026
2 of 3 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

16-20: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

ci.yml과 ci-prod.yml의 JDK 버전을 통일하세요.

현재 ci.yml은 JDK 17을, ci-prod.yml은 JDK 21을 사용합니다. 개발 환경과 프로덕션 환경에서 서로 다른 Java 버전을 사용하면 dev에서 통과한 코드가 prod에서 실패할 수 있습니다. 두 워크플로우의 JDK 버전을 일치시키거나, 의도적인 차이라면 주석으로 명시해주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 16 - 20, ci.yml currently sets
java-version: '17' while ci-prod.yml uses '21'; make these consistent by
updating the actions/setup-java@v4 step (the "Set up JDK 17" / java-version
field) so both workflows use the same JDK version, or if the difference is
intentional, add a clear comment near the actions/setup-java@v4 step explaining
why dev and prod differ; update the java-version value and/or add the comment in
both workflow files (the setup-java step) so the mismatch is resolved or
documented.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/cd-prod.yml:
- Around line 82-89: The current assignment to .environment replaces the entire
environment array and wipes out any pre-existing variables; instead update the
code that assigns .environment so it merges/updates entries rather than
overwriting: locate the .environment = [...] block and change the logic to
iterate over the listed names (SPRING_PROFILES_ACTIVE, SERVER_PORT,
EUREKA_ENABLED, EUREKA_HOST, EUREKA_PORT, JWT_SECRET) and for each, update the
existing env entry with the same "name" if present or append a new entry if not,
preserving all other existing environment variables in the task definition.
- Around line 28-30: The workflow currently allows workflow_run triggers from
any successful run which causes PR-built runs to trigger CD but not push image
steps; update the top-level if condition that currently checks
"github.event_name == 'workflow_dispatch' || (github.event_name ==
'workflow_run' && github.event.workflow_run.conclusion == 'success')" to also
require the workflow_run originated from a push to main (e.g., add checks like
"github.event_name == 'workflow_dispatch' || (github.event_name ==
'workflow_run' && github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main')") so only successful
push-to-main workflow_runs trigger the CD flow and the "Verify image exists in
ECR" step will only run when the image was actually pushed.
- Around line 77-88: The JWT_SECRET is being injected as a plaintext environment
variable into the ECS task definition; change the template to place it in the
container's secrets with valueFrom instead of in .environment. Specifically,
remove the {"name":"JWT_SECRET","value":$JWT_SECRET} entry from the .environment
array in the .containerDefinitions mapping and add a .secrets entry such as
{"name":"JWT_SECRET","valueFrom":$JWT_SECRET_ARN} (or a similarly named template
arg), update the workflow args to pass the secret ARN/SSM path (e.g., replace
--arg JWT_SECRET with --arg JWT_SECRET_ARN or add a new arg) and ensure the
value supplied comes from Secrets Manager or SSM Parameter Store via repository
secrets so the ECS task uses secrets.valueFrom rather than plaintext
environment.

In @.github/workflows/ci-prod.yml:
- Around line 41-45: The "Configure AWS credentials (OIDC)" job step is
currently unconditional and runs for pull_request events; guard it the same as
the image-push steps by adding if: github.event_name == 'push' to that step so
AWS OIDC/role-to-assume is only configured on push events; update the step that
uses aws-actions/configure-aws-credentials@v4 (the Configure AWS credentials
(OIDC) step) to include the if condition and keep role-to-assume and aws-region
inputs unchanged.

In `@build.gradle`:
- Line 41: The dependency
'org.springframework.boot:spring-boot-starter-actuator' is declared twice;
remove the duplicate declaration and keep only one entry for implementation
'org.springframework.boot:spring-boot-starter-actuator' (remove either the
occurrence at the location matching the diff showing Line 41 or the earlier
declaration at Line 25) so the build.gradle contains a single actuator
dependency entry.

In
`@src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java`:
- Line 31: Remove `/actuator/info` from the list of publicly permitted endpoints
in SecurityConfig so only `/actuator/health` remains exposed; locate the
authorizeRequests/antMatchers(...) call (inside SecurityConfig, e.g., the
configure(HttpSecurity) method or wherever permitAll is invoked) and edit the
antMatchers/permitAll array to omit "/actuator/info", leaving other entries like
"/api/*/users/signup" and "/actuator/health" unchanged.

In `@src/main/resources/application-prod.yml`:
- Around line 29-30: The production config currently exposes detailed health
info (health.show-details: always) while SecurityConfig leaves /actuator/health
and /actuator/info public; change health.show-details in application-prod.yml
from "always" to "when-authorized" (or "never" if you prefer no details at all)
and update SecurityConfig to stop permitting anonymous access to
/actuator/health and /actuator/info (require authentication or a specific role
such as ROLE_ACTUATOR) so that detailed health payloads are only returned to
authorized callers; target the health.show-details setting and the
SecurityConfig class (the permitAll/antMatchers for /actuator/*) when making
these edits.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 16-20: ci.yml currently sets java-version: '17' while ci-prod.yml
uses '21'; make these consistent by updating the actions/setup-java@v4 step (the
"Set up JDK 17" / java-version field) so both workflows use the same JDK
version, or if the difference is intentional, add a clear comment near the
actions/setup-java@v4 step explaining why dev and prod differ; update the
java-version value and/or add the comment in both workflow files (the setup-java
step) so the mismatch is resolved or documented.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f30a9ca3-5a65-4b14-b3b9-3235bf22df03

📥 Commits

Reviewing files that changed from the base of the PR and between fa92327 and 7b95d07.

📒 Files selected for processing (7)
  • .github/workflows/cd-prod.yml
  • .github/workflows/ci-prod.yml
  • .github/workflows/ci.yml
  • build.gradle
  • src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java
  • src/main/resources/application-prod.yml
  • src/main/resources/application.yml

Comment on lines +28 to +30
if: >
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

fd -type f -name "*.yml" -o -name "*.yaml" | grep -E "(workflow|github)" | head -20

Repository: Miche-Let/api-gateway

Length of output: 236


🏁 Script executed:

ls -la .github/workflows/ 2>/dev/null || echo "workflows directory not found"

Repository: Miche-Let/api-gateway

Length of output: 491


🏁 Script executed:

cat .github/workflows/cd-prod.yml

Repository: Miche-Let/api-gateway

Length of output: 4100


🏁 Script executed:

cat .github/workflows/ci-prod.yml 2>/dev/null || cat .github/workflows/ci.yml 2>/dev/null || fd -type f -name "*ci*" .github/workflows/

Repository: Miche-Let/api-gateway

Length of output: 1571


PR 성공 후에도 배포 잡이 실행되어 이미지 검증에서 실패합니다.

CI-PRODpull_requestpush 이벤트 모두에서 실행되지만, 여기서는 성공 여부만 확인하므로 성공한 PR 빌드도 CD 워크플로우를 트리거합니다. 그러나 이미지 푸시는 if: github.event_name == 'push' 조건으로 push 이벤트에서만 실행되므로, PR에서 트리거된 실행은 ECR에 이미지를 푸시하지 않습니다. 이로 인해 line 52의 "Verify image exists in ECR" 단계에서 매번 실패합니다. workflow_run 트리거를 push 이벤트와 main 브랜치로 제한해야 합니다.

제안 수정
    if: >
      github.event_name == 'workflow_dispatch' ||
-     (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
+     (github.event_name == 'workflow_run' &&
+      github.event.workflow_run.conclusion == 'success' &&
+      github.event.workflow_run.event == 'push' &&
+      github.event.workflow_run.head_branch == 'main')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if: >
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
if: >
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/cd-prod.yml around lines 28 - 30, The workflow currently
allows workflow_run triggers from any successful run which causes PR-built runs
to trigger CD but not push image steps; update the top-level if condition that
currently checks "github.event_name == 'workflow_dispatch' || (github.event_name
== 'workflow_run' && github.event.workflow_run.conclusion == 'success')" to also
require the workflow_run originated from a push to main (e.g., add checks like
"github.event_name == 'workflow_dispatch' || (github.event_name ==
'workflow_run' && github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main')") so only successful
push-to-main workflow_runs trigger the CD flow and the "Verify image exists in
ECR" step will only run when the image was actually pushed.

Comment on lines +77 to +88
--arg JWT_SECRET "${{ secrets.JWT_SECRET }}" \
'
.containerDefinitions |= map(
if .name == $CN then
.image = $IMG
| .environment = [
{"name":"SPRING_PROFILES_ACTIVE","value":$SPRING_PROFILES_ACTIVE},
{"name":"SERVER_PORT","value":$SERVER_PORT},
{"name":"EUREKA_ENABLED","value":$EUREKA_ENABLED},
{"name":"EUREKA_HOST","value":$EUREKA_HOST},
{"name":"EUREKA_PORT","value":$EUREKA_PORT},
{"name":"JWT_SECRET","value":$JWT_SECRET}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the file
fd -type f "cd-prod.yml" .github/workflows/

Repository: Miche-Let/api-gateway

Length of output: 236


🏁 Script executed:

# Once found, examine lines 77-88 and surrounding context
sed -n '70,95p' .github/workflows/cd-prod.yml | cat -n

Repository: Miche-Let/api-gateway

Length of output: 1432


🏁 Script executed:

# Check if JWT_SECRET is used elsewhere in the workflow
rg "JWT_SECRET" .github/workflows/cd-prod.yml -n -B2 -A2

Repository: Miche-Let/api-gateway

Length of output: 562


🏁 Script executed:

# Check the full workflow file to understand the context better
wc -l .github/workflows/cd-prod.yml

Repository: Miche-Let/api-gateway

Length of output: 99


🏁 Script executed:

# Look at the complete jq command and the task definition registration
sed -n '60,120p' .github/workflows/cd-prod.yml | cat -n

Repository: Miche-Let/api-gateway

Length of output: 2881


🏁 Script executed:

# Check if there are any other references to task definitions or secrets
rg "taskDefinition|secrets|Secrets Manager|SSM Parameter" .github/workflows/cd-prod.yml -n

Repository: Miche-Let/api-gateway

Length of output: 359


🏁 Script executed:

# Check if JWT_SECRET_ARN or similar variables are defined elsewhere
rg "JWT_SECRET|SECRET" .github/workflows/ -n --max-count 20

Repository: Miche-Let/api-gateway

Length of output: 252


🌐 Web query:

ECS task definition secrets valueFrom best practices AWS

💡 Result:

To securely manage secrets in AWS ECS using the valueFrom parameter, follow these best practices: 1. Use Managed Services: Store sensitive data in AWS Secrets Manager or AWS Systems Manager (SSM) Parameter Store [1][2]. Both services use AWS KMS for encryption at rest [1][3]. - Use Secrets Manager for secrets requiring automatic rotation, cross-account access, or multi-Region replication [1][3]. - Use SSM Parameter Store for basic configuration data and secrets that do not require these advanced features, as it is often more cost-effective [1][3]. 2. Use the Secrets Parameter: In your ECS task definition, use the secrets container definition parameter to reference these secrets via their ARN [4][5][6]. This allows the ECS agent to inject the secret value as an environment variable at container startup [7]. 3. Implement Least Privilege IAM: Ensure your task execution role has the minimum necessary permissions to retrieve secrets from the specific Secrets Manager or SSM Parameter Store resources [4][8][2]. 4. Consider Programmatic Retrieval for Dynamic Updates: Injecting secrets as environment variables via the task definition requires a task restart to pick up changes if a secret is rotated [6][7][2]. If your application requires real-time secret updates without restarting the task, modify your application code to retrieve secrets directly from Secrets Manager or SSM Parameter Store at runtime using the AWS SDK [8][2]. 5. Mitigate Environment Variable Exposure: Environment variables can sometimes be exposed in logs or via tools like docker inspect [1]. To further enhance security: - Use IAM roles to restrict access to the task definition and the secrets themselves [1][2]. - If extreme security is required, consider having a sidecar container retrieve the secret and write it to a shared volume, or have the application read directly from the secret store at runtime to avoid environment variables entirely [1][2]. - Ensure your logging configuration does not capture or log environment variables [2]. 6. Use Hierarchical Naming: When using SSM Parameter Store, adopt a consistent naming hierarchy (e.g., /app/env/key) to simplify IAM policy management and improve organization [9].

Citations:


🌐 Web query:

ECS environment vs secrets field security best practices

💡 Result:

In Amazon ECS, the primary security best practice for handling sensitive data is to avoid hardcoding secrets in task definitions or Dockerfiles [1][2][3]. Instead, you should use the native secrets integration provided by the ECS task definition, which allows you to reference secrets stored in AWS Secrets Manager or AWS Systems Manager Parameter Store [1][4][5]. Comparison of Approaches: 1. ECS Secrets Field (Recommended): By using the secrets parameter in your container definition, ECS automatically retrieves the secret value from Secrets Manager or Parameter Store at runtime and injects it into the container [6][7]. This method ensures that sensitive values are not stored in plain text within your task definition or version control systems [3]. 2. Environment Variables (Standard): When you use the secrets field, ECS typically exposes these values as environment variables within the container [1][6][7]. While this is the standard and supported way to inject secrets, it carries inherent risks: environment variables can sometimes be exposed through logs, error messages, or by unauthorized processes inspecting the container (e.g., via docker inspect) [1][2]. Advanced Security Best Practices: To mitigate the risks associated with environment variables, consider these more secure patterns: - Direct SDK Retrieval: For highly sensitive applications, configure your application code to use the AWS SDK to fetch secrets directly from Secrets Manager or Parameter Store at runtime [1][2]. This avoids exposing the secret as an environment variable entirely [2]. - Sidecar Pattern: Run a sidecar container that retrieves the secret and writes it to a shared, memory-backed volume (tmpfs) [1][8]. Your main application container can then read the secret from this file, ensuring the secret never exists as an environment variable and resides only in memory [1][8]. - IAM Least Privilege: Regardless of the injection method, always use an IAM task execution role with the minimum necessary permissions to access only the specific secrets required by that task [1][8][2]. - Secret Rotation: Utilize AWS Secrets Manager to enable automatic secret rotation, which limits the window of opportunity if a secret is ever compromised [1][2]. In summary, while using the ECS secrets field is significantly more secure than hardcoding values, the most robust security posture involves either direct SDK retrieval or using a sidecar pattern to keep secrets out of the environment variable space [1][8][2].

Citations:


JWT_SECRET를 환경변수로 평문 저장하지 마세요.

ECS 태스크 정의 리비전에 평문으로 저장되어 ecs:DescribeTaskDefinition 권한만으로도 노출됩니다. AWS 보안 모범 사례에 따라 JWT_SECRETenvironment이 아닌 ECS secrets 필드의 valueFrom으로 Secrets Manager 또는 SSM Parameter Store를 참조하도록 변경하세요.

제안 수정
-            --arg JWT_SECRET "${{ secrets.JWT_SECRET }}" \
+            --arg JWT_SECRET_ARN "${{ vars.JWT_SECRET_ARN }}" \
             '
             .containerDefinitions |= map(
               if .name == $CN then
                 .image = $IMG
                 | .environment = [
                     {"name":"SPRING_PROFILES_ACTIVE","value":$SPRING_PROFILES_ACTIVE},
                     {"name":"SERVER_PORT","value":$SERVER_PORT},
                     {"name":"EUREKA_ENABLED","value":$EUREKA_ENABLED},
                     {"name":"EUREKA_HOST","value":$EUREKA_HOST},
-                    {"name":"EUREKA_PORT","value":$EUREKA_PORT},
-                    {"name":"JWT_SECRET","value":$JWT_SECRET}
+                    {"name":"EUREKA_PORT","value":$EUREKA_PORT}
                   ]
+                | .secrets = (
+                    ((.secrets // []) | map(select(.name != "JWT_SECRET")))
+                    + [{"name":"JWT_SECRET","valueFrom":$JWT_SECRET_ARN}]
+                  )
               else .
               end
             )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/cd-prod.yml around lines 77 - 88, The JWT_SECRET is being
injected as a plaintext environment variable into the ECS task definition;
change the template to place it in the container's secrets with valueFrom
instead of in .environment. Specifically, remove the
{"name":"JWT_SECRET","value":$JWT_SECRET} entry from the .environment array in
the .containerDefinitions mapping and add a .secrets entry such as
{"name":"JWT_SECRET","valueFrom":$JWT_SECRET_ARN} (or a similarly named template
arg), update the workflow args to pass the secret ARN/SSM path (e.g., replace
--arg JWT_SECRET with --arg JWT_SECRET_ARN or add a new arg) and ensure the
value supplied comes from Secrets Manager or SSM Parameter Store via repository
secrets so the ECS task uses secrets.valueFrom rather than plaintext
environment.

Comment on lines +82 to +89
| .environment = [
{"name":"SPRING_PROFILES_ACTIVE","value":$SPRING_PROFILES_ACTIVE},
{"name":"SERVER_PORT","value":$SERVER_PORT},
{"name":"EUREKA_ENABLED","value":$EUREKA_ENABLED},
{"name":"EUREKA_HOST","value":$EUREKA_HOST},
{"name":"EUREKA_PORT","value":$EUREKA_PORT},
{"name":"JWT_SECRET","value":$JWT_SECRET}
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the workflow file
find . -name "cd-prod.yml" -type f 2>/dev/null

Repository: Miche-Let/api-gateway

Length of output: 97


🏁 Script executed:

# Let's check if the file exists and read the relevant section
if [ -f ".github/workflows/cd-prod.yml" ]; then
  echo "=== Lines 70-100 of cd-prod.yml ===" 
  sed -n '70,100p' ".github/workflows/cd-prod.yml" | cat -n
else
  echo "File not found, checking directory structure..."
  find . -path "*workflows*" -name "*.yml" -o -name "*.yaml" | head -20
fi

Repository: Miche-Let/api-gateway

Length of output: 1663


🏁 Script executed:

# Get the full content of the workflow file to understand the context better
if [ -f ".github/workflows/cd-prod.yml" ]; then
  wc -l ".github/workflows/cd-prod.yml"
  echo "=== Full relevant section ===" 
  cat -n ".github/workflows/cd-prod.yml" | sed -n '75,95p'
fi

Repository: Miche-Let/api-gateway

Length of output: 1225


컨테이너 환경변수를 완전히 교체하고 있습니다.

Line 82의 .environment = [...] 할당은 기존 환경변수 배열 전체를 새로운 배열로 교체하므로, task definition에 이미 설정된 다른 런타임 환경변수가 모두 손실됩니다. 필요한 변수들만 갱신/추가하도록 merge 작업으로 변경해야 배포 시 설정 유실을 방지할 수 있습니다.

제안 수정
-                | .environment = [
-                    {"name":"SPRING_PROFILES_ACTIVE","value":$SPRING_PROFILES_ACTIVE},
-                    {"name":"SERVER_PORT","value":$SERVER_PORT},
-                    {"name":"EUREKA_ENABLED","value":$EUREKA_ENABLED},
-                    {"name":"EUREKA_HOST","value":$EUREKA_HOST},
-                    {"name":"EUREKA_PORT","value":$EUREKA_PORT},
-                    {"name":"JWT_SECRET","value":$JWT_SECRET}
-                  ]
+                | .environment = (
+                    ((.environment // []) | map({key: .name, value: .value}) | from_entries)
+                    + {
+                        "SPRING_PROFILES_ACTIVE": $SPRING_PROFILES_ACTIVE,
+                        "SERVER_PORT": $SERVER_PORT,
+                        "EUREKA_ENABLED": $EUREKA_ENABLED,
+                        "EUREKA_HOST": $EUREKA_HOST,
+                        "EUREKA_PORT": $EUREKA_PORT,
+                        "JWT_SECRET": $JWT_SECRET
+                      }
+                    | to_entries
+                    | map({"name": .key, "value": .value})
+                  )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/cd-prod.yml around lines 82 - 89, The current assignment
to .environment replaces the entire environment array and wipes out any
pre-existing variables; instead update the code that assigns .environment so it
merges/updates entries rather than overwriting: locate the .environment = [...]
block and change the logic to iterate over the listed names
(SPRING_PROFILES_ACTIVE, SERVER_PORT, EUREKA_ENABLED, EUREKA_HOST, EUREKA_PORT,
JWT_SECRET) and for each, update the existing env entry with the same "name" if
present or append a new entry if not, preserving all other existing environment
variables in the task definition.

Comment on lines +41 to +45
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/ci-prod.yml

Repository: Miche-Let/api-gateway

Length of output: 1984


PR 검증에서도 AWS 인증을 시도합니다.

Line 41-45의 Configure AWS credentials (OIDC) 단계는 if 조건이 없어서 pull_request에서도 실행됩니다. 하지만 이미지 푸시 관련 모든 단계(line 48, 52, 57)는 if: github.event_name == 'push'로 보호되어 있으므로, AWS 인증도 동일하게 보호해야 합니다. 현재 상태에서는 PR 검증 시 불필요하게 프로덕션 AWS role/OIDC에 접근하려 시도하며, PR 컨텍스트에서 권한이 없으면 실패할 수 있습니다.

제안 수정
       - name: Configure AWS credentials (OIDC)
+        if: github.event_name == 'push'
         uses: aws-actions/configure-aws-credentials@v4
         with:
           role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
           aws-region: ${{ vars.AWS_REGION }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- name: Configure AWS credentials (OIDC)
if: github.event_name == 'push'
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci-prod.yml around lines 41 - 45, The "Configure AWS
credentials (OIDC)" job step is currently unconditional and runs for
pull_request events; guard it the same as the image-push steps by adding if:
github.event_name == 'push' to that step so AWS OIDC/role-to-assume is only
configured on push events; update the step that uses
aws-actions/configure-aws-credentials@v4 (the Configure AWS credentials (OIDC)
step) to include the if condition and keep role-to-assume and aws-region inputs
unchanged.

Comment thread build.gradle
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'org.springframework.boot:spring-boot-starter-actuator'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify duplicate actuator declarations in Gradle dependencies
rg -n "spring-boot-starter-actuator" build.gradle

Repository: Miche-Let/api-gateway

Length of output: 215


spring-boot-starter-actuator 의존성이 중복 선언되어 있습니다.

Line 41은 Line 25와 동일한 의존성이므로 중복입니다. 하나만 유지하세요.

🔧 제안 수정
-	implementation 'org.springframework.boot:spring-boot-starter-actuator'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
implementation 'org.springframework.boot:spring-boot-starter-actuator'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build.gradle` at line 41, The dependency
'org.springframework.boot:spring-boot-starter-actuator' is declared twice;
remove the duplicate declaration and keep only one entry for implementation
'org.springframework.boot:spring-boot-starter-actuator' (remove either the
occurrence at the location matching the diff showing Line 41 or the earlier
declaration at Line 25) so the build.gradle contains a single actuator
dependency entry.

"/api/*/auth/login",
"/api/*/auth/reissue",
"/api/*/users/signup"
"/api/*/users/signup", "/actuator/health", "/actuator/info"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify where /actuator/info is publicly exposed or referenced
rg -n "/actuator/info|permitAll\\(|management\\.endpoint\\.info|endpoints\\.web\\.exposure" \
  src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java \
  src/main/resources/application-prod.yml \
  src/main/resources/application.yml

Repository: Miche-Let/api-gateway

Length of output: 355


🏁 Script executed:

# SecurityConfig.java 전체 내용 확인
cat -n src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java

Repository: Miche-Let/api-gateway

Length of output: 2979


🏁 Script executed:

# 애플리케이션 설정 파일에서 actuator 관련 설정 확인
cat src/main/resources/application.yml
cat src/main/resources/application-prod.yml 2>/dev/null || echo "application-prod.yml not found"

Repository: Miche-Let/api-gateway

Length of output: 2715


🏁 Script executed:

# actuator 엔드포인트 관련 다른 참조 확인
rg -n "actuator" src/main/

Repository: Miche-Let/api-gateway

Length of output: 237


/actuator/info는 공개 허용 대상에서 제외하는 것이 안전합니다.

Line 31에서 /actuator/info까지 permitAll로 열려 있습니다. 프로덕션 헬스체크 목적이면 /actuator/health만 공개하는 편이 안전합니다. /actuator/info는 애플리케이션 이름, 버전, 빌드 정보 등 메타데이터를 노출하므로 제거하여 정보 공개 최소화 원칙을 따르는 것이 권장됩니다.

🔧 제안 수정
-                                "/api/*/users/signup", "/actuator/health", "/actuator/info"
+                                "/api/*/users/signup", "/actuator/health"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java`
at line 31, Remove `/actuator/info` from the list of publicly permitted
endpoints in SecurityConfig so only `/actuator/health` remains exposed; locate
the authorizeRequests/antMatchers(...) call (inside SecurityConfig, e.g., the
configure(HttpSecurity) method or wherever permitAll is invoked) and edit the
antMatchers/permitAll array to omit "/actuator/info", leaving other entries like
"/api/*/users/signup" and "/actuator/health" unchanged.

Comment on lines +29 to +30
health:
show-details: always

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify risky combination across prod config + security config
rg -n "show-details|/actuator/health|/actuator/info" \
  src/main/resources/application-prod.yml \
  src/main/java/com/michelet/gateway/infrastructure/config/SecurityConfig.java

Repository: Miche-Let/api-gateway

Length of output: 307


공개 헬스 엔드포인트와 show-details: always 조합은 내부 정보 노출 보안 위험을 초래합니다.

SecurityConfig에서 /actuator/health/actuator/info가 인증 없이 공개되어 있고, application-prod.yml의 line 30에서 show-details: always로 설정되어 있습니다. 이 조합은 인증되지 않은 사용자가 애플리케이션의 상세한 내부 상태 정보(데이터베이스, 디스크, 캐시 등)에 접근할 수 있게 하므로 운영 환경에서 즉시 수정이 필요합니다.

🔧 제안 수정
 management:
   endpoint:
     health:
-      show-details: always
+      show-details: when-authorized
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
health:
show-details: always
health:
show-details: when-authorized
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/application-prod.yml` around lines 29 - 30, The production
config currently exposes detailed health info (health.show-details: always)
while SecurityConfig leaves /actuator/health and /actuator/info public; change
health.show-details in application-prod.yml from "always" to "when-authorized"
(or "never" if you prefer no details at all) and update SecurityConfig to stop
permitting anonymous access to /actuator/health and /actuator/info (require
authentication or a specific role such as ROLE_ACTUATOR) so that detailed health
payloads are only returned to authorized callers; target the health.show-details
setting and the SecurityConfig class (the permitAll/antMatchers for /actuator/*)
when making these edits.

@coderabbitai coderabbitai Bot mentioned this pull request May 17, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jun 6, 2026
Merged
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.

[FEAT] prod 설정 및 cd 로직 추가

1 participant