198 lines
24 KiB
Markdown
198 lines
24 KiB
Markdown
# Redis 설정은 어떻게 실패하는가: 바인딩·검증·Secret·Credential 추적
|
|
|
|
> **Redis 코드 상세 시리즈 04/20** · [전체 지도](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-backend-policy-boundary.md) · 이전: [app.redis.enabled에서 capability bean까지: Spring 조립 코드 읽기](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-spring-composition.md) · 다음: [하나의 설정에서 세 topology로: RedisTopologyClientFactory 코드 읽기](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-topology-client-factory.md)
|
|
|
|
## 이 글이 답하는 코드 질문
|
|
|
|
Redis 설정에는 endpoint, topology, timeout, pool ceiling, TLS, ACL account가 함께 들어갑니다. 이 값들은 언제 binding되고, 어느 단계에서 거절되며, `secret://...` reference는 어떻게 실제 username/password가 될까요? 이 글은 Spring property에서 `RedisURI`에 전달될 credential까지의 경로와 현재 environment/secret registry drift를 구분합니다.
|
|
|
|
## 코드 지도
|
|
|
|
| 코드 | 입력 | 출력 | 실패 위치 |
|
|
|---|---|---|---|
|
|
| [`RedisSdkSettings`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:9) | `app.redis.*` | typed 설정과 warning 목록 | `validate()` |
|
|
| [`RedisSdkAutoConfiguration.redisSdkSettings()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:83) | Spring binder | bound settings bean | binding failure |
|
|
| [`RedisCredentialResolver`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCredentialResolver.java:7) | purpose + `secret://<source>/<name>` | optional `RedisCredentials` | malformed/unresolved reference |
|
|
| [`RedisResolvedCredentials`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:354) | role별 credential | immutable role map + Sentinel credential | client factory 이전 |
|
|
| [`SecretSourceConfig`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/SecretSourceConfig.java:8) | strategy + environment | application `SecretSource` | backend 생성 |
|
|
| [`SecretSourceValidator`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/SecretSourceValidator.java:11) | profile, role selectors, secret source | prod secret contract | singleton 초기화 종료 시점 |
|
|
| [`env-keys.yaml`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/env-keys.yaml:1885) | 환경 키 계약 | 분류·기본값·required_when | registry test/build gate |
|
|
| [`secrets-classification.yaml`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/secrets-classification.yaml:78) | secret 이름 | source·rotation·masking 계약 | registry contract test |
|
|
|
|
## Redis-off에서는 binding도 하지 않습니다
|
|
|
|
`RedisSdkSettings`에는 일부 유효한 local default가 있지만 class 자체에는 `@ConfigurationProperties`가 없습니다. 이유는 [`class 설명](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:17)에 적혀 있습니다. application-wide scan이 이 type을 발견하면 Redis를 쓰지 않는 deployment도 값을 binding하고 검증하게 됩니다.
|
|
|
|
실제 등록은 `app.redis.enabled=true` 조건 아래의 [`redisSdkSettings()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:83)만 합니다. switch가 없거나 false이면 다음 모두 생략됩니다.
|
|
|
|
- `app.redis.*` binding
|
|
- cross-field validation
|
|
- credential reference resolution
|
|
- raw allowlist와 TLS material 읽기
|
|
- client/event loop/runtime owner 생성
|
|
|
|
[`disabledIgnoresMalformedRedisConfiguration()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfigurationTest.java:71)은 switch-off 상태에서 Cluster non-zero database, 빈 nodes, zero timeout 같은 값도 context에 영향을 주지 않는다고 고정합니다.
|
|
|
|
## bind → validate → resolve 순서
|
|
|
|
Spring은 factory method가 settings 객체를 반환한 다음 configuration property를 채웁니다. 그래서 factory method 안에서 `validate()`를 부르면 아직 default만 검사하게 됩니다. 별도 validation bean이 settings에 의존하는 이유입니다.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant B as Spring Binder
|
|
participant S as RedisSdkSettings
|
|
participant V as SettingsValidation bean
|
|
participant R as RedisCredentialResolver
|
|
participant SS as RedisSecretSource
|
|
participant F as TopologyClientFactory
|
|
B->>S: app.redis.* binding
|
|
V->>S: validate()
|
|
S-->>V: warnings 또는 IllegalStateException
|
|
V->>V: raw policy resource probe
|
|
R->>SS: reference의 name resolve
|
|
SS-->>R: secret 또는 empty
|
|
R-->>F: role별 username/password
|
|
```
|
|
|
|
[`redisSdkSettingsValidation()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:101)은 warning을 log하고 raw gateway가 켜졌다면 allowlist resource가 실제로 읽히는지 확인합니다. `redisResolvedCredentials()`는 이 validation bean을 parameter로 받아 순서를 강제합니다.
|
|
|
|
## `RedisSdkSettings.validate()`가 거절하는 것
|
|
|
|
핵심 cross-field rule은 [`validate()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:58)에 모여 있습니다.
|
|
|
|
### topology와 namespace
|
|
|
|
- Cluster에서 database가 0이 아니면 거절합니다.
|
|
- 음수 database와 빈 node 목록을 거절합니다.
|
|
- Sentinel이면 `app.redis.sentinel.master-name`이 필요합니다.
|
|
- namespace의 `environment`, `service`, `domain`은 `RedisKeyRules.requireToken()`을 통과해야 합니다.
|
|
|
|
Standalone node가 정확히 하나인지, `host:port` 문법인지 여부는 settings가 아니라 topology factory가 검사합니다. settings validation이 성공해도 client factory 단계에서 실패할 수 있습니다.
|
|
|
|
### timeout과 limit
|
|
|
|
fast, collection, script, batch, admin timeout은 모두 양수이며 30초 이하여야 합니다. fast timeout이 5초를 넘으면 failure가 아니라 warning입니다. 기본값은 [`Timeouts` field](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:188)에서 각각 500ms, 2s, 1s, 2s, 3s입니다.
|
|
|
|
blocking `maxBlock`은 양수여야 하고 blocking/transaction connection ceiling도 1 이상이어야 합니다. key/value/stream/hash/batch/scan/offline queue/bitmap limit은 모두 양수이며 key byte limit은 `RedisKeyRules.MAX_KEY_BYTES`를 넘을 수 없습니다. capacity의 in-flight command/byte/reply ceiling도 양수여야 합니다.
|
|
|
|
여기서 양수 검증과 runtime 적용을 구분해야 합니다. [`limits.offlineQueueCommands`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:250)는 기본값이 1,000이고 1 미만이면 거절되지만, production main source에서 [`getOfflineQueueCommands()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:344)를 호출하는 코드는 없습니다. Lettuce의 실제 `requestQueueSize`는 이 값이 아니라 [`capacity.maximumInFlightCommands`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisTopologyClientFactory.java:307)를 사용합니다. 두 기본값도 각각 1,000과 64로 다릅니다.
|
|
|
|
### TLS와 lifecycle
|
|
|
|
mTLS client certificate를 지정했는데 client key reference가 없으면 실패합니다. TLS가 켜졌지만 hostname verification을 끄면 warning입니다. lifecycle은 nonblank client name, positive connect/TLS-handshake/acquire/shutdown/drain timeout, nonnegative quiet period, `quietPeriod <= shutdownTimeout`을 요구합니다. 이 규칙은 [`Lifecycle.validate()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:568)에 있습니다.
|
|
|
|
현재 `tlsHandshakeTimeout`과 `acquireTimeout`도 binding과 validation은 되지만 production 사용처가 getter 외에는 확인되지 않습니다. owner는 pool 포화 시 즉시 거절하며 acquire timeout 동안 대기하지 않습니다. 이들 setting과 `offlineQueueCommands`를 runtime에 적용된 값으로 설명하면 안 됩니다.
|
|
|
|
### raw, admin, advanced
|
|
|
|
raw gateway가 켜지면 nonblank policy resource와 raw 전용 credential reference가 필요합니다. admin plane이 켜지면 admin credential reference가 필요합니다. advanced operation이 꺼진 상태에서 advanced policies를 설정하면 실패합니다.
|
|
|
|
raw resource의 nonblank 검사는 settings가 하고, 존재/가독성 검사는 [`requireRawPolicyResource()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:119)가 합니다. 기본 raw path는 `classpath:redis-sdk/raw-command-allowlist.yml`이지만 해당 이름의 resource를 leaf가 제공하지 않습니다. raw를 실제로 켤 때는 존재하는 resource로 명시해야 합니다.
|
|
|
|
### authentication
|
|
|
|
application credential reference가 없으면 기본적으로 startup failure입니다. local anonymous Redis를 쓰려면 `app.redis.authentication.anonymous-access-accepted=true`를 명시해야 하고, 이 경우 warning을 남깁니다. advanced credential이 없으면 script가 application account로 fallback한다는 warning을 남깁니다. [`Authentication.validate()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:406)가 이 두 trade-off를 구분합니다.
|
|
|
|
## credential reference 해석
|
|
|
|
허용 문법은 `secret://<source>/<name>`입니다. named ACL user를 지정하려면 source segment를 `<user>@<source>`로 씁니다.
|
|
|
|
예를 들어 `secret://ca-skeleton-application@environment/APP_REDIS_PASSWORD`는 다음으로 분해됩니다.
|
|
|
|
- scheme: `secret://`
|
|
- ACL username: `ca-skeleton-application`
|
|
- source label: `environment`
|
|
- secret name: `APP_REDIS_PASSWORD`
|
|
|
|
[`RedisCredentialResolver.resolve()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCredentialResolver.java:45)는 reference가 blank이면 `Optional.empty()`를 반환합니다. scheme이 다르거나 source/name separator가 없으면 configuration error입니다. secret source가 null/blank 값을 반환하면 connection 생성 전 startup failure입니다.
|
|
|
|
source segment에 `@`가 없으면 username은 `default`입니다. 이 동작은 [`usernameOf()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCredentialResolver.java:100)에 있습니다. `RedisCredentials.toString()`은 password를 `***`로 바꿔 출력합니다.
|
|
|
|
`source` 문자열은 현재 backend routing에 쓰이지 않습니다. resolver는 마지막 path name만 `secretSource.apply(name)`에 넘깁니다. 즉 `secret://vault/NAME`이라고 써도 `vault` backend를 자동 선택하지 않습니다. 실제 backend는 application의 `SecretSourceConfig`가 선택합니다.
|
|
|
|
## 역할별 credential과 fallback
|
|
|
|
[`redisResolvedCredentials()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:156)은 다음 순서로 account를 해석합니다.
|
|
|
|
1. `APPLICATION`
|
|
2. `ADVANCED`
|
|
3. `PUBSUB`
|
|
4. admin enabled일 때 `ADMIN`
|
|
5. raw enabled일 때 `RAW`
|
|
6. Sentinel mode일 때 별도 Sentinel control credential
|
|
|
|
설정되지 않은 advanced/pubsub role은 map에 들어가지 않습니다. topology factory의 role router가 해당 lane을 application client로 보냅니다. admin과 raw는 enabled 상태에서 reference가 필수이므로 암묵적으로 application account에 내려가지 않습니다.
|
|
|
|
Sentinel credential은 data primary account와 다릅니다. Sentinel control plane이 primary 위치를 조회할 때 쓸 credential이고 application credential은 발견된 primary에 명령을 보낼 때 씁니다.
|
|
|
|
## application SecretSource와 prod validator
|
|
|
|
기본 application backend는 [`EnvironmentSecretSource`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/EnvironmentSecretSource.java:10)입니다. Spring `Environment`에서 key를 읽고 null/blank를 empty로 바꿉니다. [`SecretSourceFactory`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/SecretSourceFactory.java:13)의 enum switch에는 현재 `ENVIRONMENT`만 있습니다.
|
|
|
|
`RedisCapabilityConfig.redisSdkSecretSource()`가 application `SecretSource`를 SDK interface에 연결합니다. 따라서 정상적인 `app-bootstrap` 실행에서는 SDK의 `System.getenv()` fallback 대신 configured backend를 사용합니다.
|
|
|
|
[`SecretSourceValidator.afterSingletonsInstantiated()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/SecretSourceValidator.java:60)은 prod profile에서 두 검사를 합니다.
|
|
|
|
- property source에 `__LOCAL_DEV_` prefix 값이 있으면 거절합니다.
|
|
- `REQUIRED_PROD_SECRETS` 중 현재 Redis role에 필요한 secret이 없으면 거절합니다.
|
|
|
|
Redis secret은 global switch와 role selector가 모두 맞을 때만 요구됩니다. cache, rate-limit, session, idempotency, lease prefix를 따로 판정하며 알 수 없는 Redis role은 Redis-on일 때 fail-closed로 요구합니다.
|
|
|
|
## environment/secret registry drift
|
|
|
|
현재 production code와 registry 사이에는 중요한 불일치가 있습니다.
|
|
|
|
첫째, SDK와 topology tests는 application credential 예시로 `APP_REDIS_PASSWORD`를 사용합니다. 그러나 `env-keys.yaml`과 `secrets-classification.yaml`에는 `APP_REDIS_PASSWORD` entry가 확인되지 않습니다. 대신 classification registry는 [`APP_CACHE_REDIS_PASSWORD`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/secrets-classification.yaml:78), [`APP_RATE_LIMIT_REDIS_PASSWORD`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/secrets-classification.yaml:116), [`APP_SESSION_REDIS_PASSWORD`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/secrets-classification.yaml:152) 같은 이전 role별 이름을 유지합니다.
|
|
|
|
둘째, `SecretSourceValidator.REQUIRED_PROD_SECRETS`도 이 role별 legacy secret 이름을 요구합니다. 반면 SDK는 `app.redis.authentication.credential-reference`에 적힌 임의의 `<name>`을 해석합니다. validator는 실제 reference target을 읽지 않습니다.
|
|
|
|
그 결과 prod deployment가 `APP_REDIS_PASSWORD`를 올바르게 주입하고 reference를 그 이름으로 설정해도, 선택한 role에 따라 `APP_CACHE_REDIS_PASSWORD`나 `APP_RATE_LIMIT_REDIS_PASSWORD`가 없다는 별도 startup failure를 만날 수 있습니다. 반대로 registry가 요구한 role별 password가 있어도 SDK reference가 다른 이름을 가리키면 SDK resolver에서 실패합니다.
|
|
|
|
셋째, `env-keys.yaml`은 `app.redis.*` typed settings가 `application.yml`에 없고 generated configuration metadata와 대조된다고 설명합니다. 이 구조는 intentional입니다. 따라서 `application.yml`에 `APP_REDIS_NODES` placeholder가 없다는 사실 자체는 drift가 아닙니다. 문제는 credential material의 실제 reference target과 prod required-secret 목록이 서로 다른 SSOT를 가진다는 점입니다.
|
|
|
|
넷째, `APP_REDIS_LIFECYCLE_ACQUIRE_TIMEOUT`과 `APP_REDIS_LIFECYCLE_TLS_HANDSHAKE_TIMEOUT`은 [`env-keys.yaml` runtime 설정 구간](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/env-keys.yaml:2394)에 등록되어 있지만 현행 runtime 적용 코드를 찾지 못했습니다. [`APP_REDIS_LIMITS_OFFLINE_QUEUE_COMMANDS`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/docs/registries/env-keys.yaml:2165)도 public configuration으로 등록되어 binding·validation되지만, 값을 바꿔도 현행 Lettuce `requestQueueSize`는 바뀌지 않습니다. 실제 queue ceiling의 입력은 `capacity.maximumInFlightCommands`입니다.
|
|
|
|
## 정상·실패 분기 요약
|
|
|
|
| 단계 | 정상 | 실패 |
|
|
|---|---|---|
|
|
| switch 조건 | off이면 완전 생략 | off + Redis role은 activation validator failure |
|
|
| binding | typed value로 변환 | duration/enum/type binding 오류 |
|
|
| settings validation | warning 또는 validated settings | cross-field `IllegalStateException` |
|
|
| resource validation | raw/TLS resource 읽기 가능 | startup failure |
|
|
| credential parse | optional role 또는 parsed reference | literal/malformed reference 거절 |
|
|
| secret resolve | nonblank secret | connection 전에 `resolved to nothing` |
|
|
| prod secret contract | selected role secret 존재 | legacy required list와 실제 reference drift 가능 |
|
|
|
|
이 구간의 failure는 command가 전송되기 전이므로 execution certainty는 `NOT_SENT` 성격입니다. 실제 authentication 실패는 connection이 lazy하게 열릴 때 발생할 수 있습니다. reference resolution 성공은 server가 password를 받아들였다는 증명이 아닙니다.
|
|
|
|
## 테스트가 고정하는 계약
|
|
|
|
[`RedisSdkSettingsTest`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettingsTest.java:1)는 topology/database, timeout, lane ceiling, TLS, raw/admin, authentication warning과 failure를 직접 고정합니다.
|
|
|
|
[`RedisSdkAutoConfigurationTest`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfigurationTest.java:130)는 configured role별 secret source 호출 횟수와 unresolved/malformed reference의 startup failure를 확인합니다. [`configuredAccountsAreResolvedPerRole()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfigurationTest.java:330)는 application/advanced/pubsub account map을 고정합니다.
|
|
|
|
[`RequiredWhenIsEnforcedTest`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RequiredWhenIsEnforcedTest.java:35)는 env registry의 `required_when` 조건을 context failure와 대조합니다. [`SecretsClassificationRegistryTest`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/contract/SecretsClassificationRegistryTest.java:1)는 validator의 required secret list와 classification registry를 1:1로 맞춥니다. 이 테스트들은 두 registry가 서로 일치함을 보이지만 SDK reference target과의 일치까지 보이지는 않습니다.
|
|
|
|
[`SecretSourceValidatorTest`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/SecretSourceValidatorTest.java:1)는 prod/local sentinel과 role별 조건을 고정합니다.
|
|
|
|
## 현재 한계와 다음 source 순서
|
|
|
|
- credential rotation은 restart-only입니다. runtime refresh/dual credential handover가 조립되지 않았습니다.
|
|
- `secret://`의 source segment는 현재 backend selector가 아니라 문법·username carrier입니다.
|
|
- `RedisStartupProbe` production 조립이 없어 reference resolution 뒤 실제 authentication과 server fact 확인은 lazy connection/request에 남습니다.
|
|
- prod required secret validator와 실제 SDK credential reference target은 정렬되지 않았습니다.
|
|
- lifecycle acquire/TLS handshake timeout과 `limits.offlineQueueCommands`는 registry와 settings에는 있으나 runtime 적용이 확인되지 않습니다. 현행 Lettuce `requestQueueSize`는 별도 capacity setting을 사용합니다.
|
|
|
|
다음에는 [`RedisSdkSettings.validate()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:58), [`RedisCredentialResolver.resolve()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCredentialResolver.java:45), [`redisResolvedCredentials()`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java:156), [`SecretSourceValidator`](/home/donghyeon/workspace/desktop-server-git/clean-architecture-backend-template/src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/SecretSourceValidator.java:94) 순서로 읽으면 됩니다.
|
|
|
|
관련 시리즈 주제는 topology별 URI/client 생성과 role별 lane routing입니다.
|
|
|
|
## 시리즈에서 이어 읽기
|
|
|
|
- 이전 글: [app.redis.enabled에서 capability bean까지: Spring 조립 코드 읽기](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-spring-composition.md)
|
|
- 다음 글: [하나의 설정에서 세 topology로: RedisTopologyClientFactory 코드 읽기](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-topology-client-factory.md)
|
|
- 전체 흐름: [Redis를 범용 클라이언트가 아니라 정책 경계로 다루기](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-backend-policy-boundary.md)
|
|
- 운영 흐름: [Redis를 켠다는 말의 운영적 의미: 단일 활성화 스위치에서 Sentinel 쓰기 손실 검증까지](/home/donghyeon/workspace/ai-tool/document-haness/.run/redis/redis-platform-sre-operations.md)
|
|
|