1111import java .net .URI ;
1212import java .net .URLEncoder ;
1313import java .nio .charset .StandardCharsets ;
14+ import java .util .List ;
1415
1516@ Component
1617public class AwsKubeConfigProvider implements KubeConfigProvider {
1718
18- @ Value ("${cbtumblebug.url}" )
19- private String tumblebugUrl ;
20-
21- @ Value ("${cbtumblebug.port}" )
22- private String tumblebugPort ;
23-
24- @ Value ("${cbtumblebug.id}" )
25- private String tumblebugId ;
26-
27- @ Value ("${cbtumblebug.pass}" )
28- private String tumblebugPassword ;
19+ @ Value ("${spider.url}" )
20+ private String spiderUrl ;
21+
22+ @ Value ("${spider.port}" )
23+ private String spiderPort ;
24+
25+ @ Override
26+ public Config buildConfig (K8sClusterDto dto ) {
27+ String yaml = dto .getAccessInfo ().getKubeconfig ();
28+ Config cfg = Config .fromKubeconfig (KubeConfigProviderFactory .replaceUrlHostByPort (yaml , spiderPort , List .of ("localhost" ), spiderUrl ));
29+ System .out .println ("------------------- kubeconfig: \n " + cfg );
30+ cfg .setTrustCerts (true );
31+ cfg .setConnectionTimeout (30_000 );
32+ cfg .setRequestTimeout (30_000 );
33+ return cfg ;
34+ }
2935
3036 @ Override
3137 public boolean supports (String providerName ) {
@@ -37,238 +43,19 @@ public String getOriginalKubeconfigYaml(K8sClusterDto dto) {
3743 if (dto == null ) {
3844 throw new IllegalArgumentException ("K8sClusterDto cannot be null" );
3945 }
40-
46+
4147 if (dto .getAccessInfo () == null ) {
42- throw new IllegalStateException ("AccessInfo is null for AWS cluster: " + dto .getName ());
48+ throw new IllegalStateException ("AccessInfo is null for Azure cluster: " + dto .getName ());
4349 }
44-
50+
4551 String kubeconfig = dto .getAccessInfo ().getKubeconfig ();
4652 if (kubeconfig == null || kubeconfig .trim ().isEmpty ()) {
47- throw new IllegalStateException ("Kubeconfig is null or empty for AWS cluster: " + dto .getName ());
53+ throw new IllegalStateException ("Kubeconfig is null or empty for Azure cluster: " + dto .getName ());
4854 }
49-
50- // AWS의 경우 localhost를 실제 Tumblebug 주소로 변경
51- return processAwsKubeconfig (kubeconfig );
52- }
53-
54- @ Override
55- public Config buildConfig (K8sClusterDto dto ) {
56- // String yaml = dto.getAccessInfo().getKubeconfig();
57- // String server = extractServer(yaml);
58- // String ca = extractCertificateAuthorityData(yaml);
59- // String clusterName = dto.getLabel().get("sys.cspResourceName");
6055
61- // String token = EksClient.builder()
62- // .region(Region.of(System.getenv("AWS_REGION")))
63- // .credentialsProvider(DefaultCredentialsProvider.create())
64- // .build()
65- // .getToken(GetTokenRequest.builder().clusterName(clusterName).build())
66- // .token();
56+ System .out .println ("------------------- kubeconfig: \n " + KubeConfigProviderFactory .replaceUrlHostByPort (kubeconfig , spiderPort , List .of ("localhost" ), spiderUrl ));
6757
68- // Config cfg = new Config();
69- // cfg.setMasterUrl(server);
70- // cfg.setCaCertData(ca);
71- // // cfg.setOauthToken(token);
72- // cfg.setTrustCerts(true);
73- // cfg.setConnectionTimeout(30_000);
74- // cfg.setRequestTimeout(30_000);
75- // return cfg;
76- return null ;
77- }
78-
79- private String extractServer (String yaml ) {
80- for (String line : yaml .split ("\\ r?\\ n" )) {
81- if (line .trim ().startsWith ("server:" )) {
82- return line .split ("server:" )[1 ].trim ();
83- }
84- }
85- throw new IllegalStateException ("server URL을 찾을 수 없습니다" );
58+ return KubeConfigProviderFactory .replaceUrlHostByPort (kubeconfig , spiderPort , List .of ("localhost" ), spiderUrl );
8659 }
8760
88- private String extractCertificateAuthorityData (String yaml ) {
89- StringBuilder sb = new StringBuilder ();
90- boolean inBlock = false ;
91- for (String line : yaml .split ("\\ r?\\ n" )) {
92- if (line .trim ().startsWith ("certificate-authority-data:" )) {
93- inBlock = true ;
94- sb .append (line .substring (line .indexOf (':' ) + 1 ).trim ());
95- } else if (inBlock && (line .startsWith (" " ) || line .startsWith ("\t " ))) {
96- sb .append (line .trim ());
97- } else if (inBlock ) {
98- break ;
99- }
100- }
101- if (sb .isEmpty ()) throw new IllegalStateException ("certificate-authority-data를 찾을 수 없습니다" );
102- return sb .toString ();
103- }
104-
105- /**
106- * AWS kubeconfig에서 localhost를 Tumblebug IP로 변경하고 exec 플러그인을 제거하여 직접 토큰 사용
107- */
108- private String processAwsKubeconfig (String kubeconfig ) {
109- System .out .println ("=== AWS kubeconfig 처리 시작 ===" );
110- try {
111- // 1. localhost만 Tumblebug IP로 변경 (포트는 그대로 유지)
112- String processedKubeconfig = kubeconfig .replace ("localhost:" , tumblebugUrl + ":" );
113- System .out .println ("1. 주소 변경: localhost -> " + tumblebugUrl );
114-
115- // 2. kubeconfig에서 cluster ID와 connection name 추출
116- String clusterId = extractClusterId (processedKubeconfig );
117- String connectionName = extractConnectionName (processedKubeconfig );
118- System .out .println ("2. 추출된 정보 - clusterId: " + clusterId + ", connectionName: " + connectionName );
119-
120- // 3. 현재 토큰 가져오기
121- System .out .println ("3. 토큰 요청 시작..." );
122- String token = getCurrentToken (clusterId , connectionName );
123- System .out .println ("4. 토큰 가져오기 성공: " + token .substring (0 , Math .min (20 , token .length ())) + "..." );
124-
125- // 4. kubeconfig에서 exec 플러그인을 제거하고 직접 토큰 설정
126- processedKubeconfig = replaceExecWithToken (processedKubeconfig , token );
127- System .out .println ("5. kubeconfig 수정 완료" );
128-
129- return processedKubeconfig ;
130- } catch (Exception e ) {
131- System .err .println ("토큰 가져오기 실패, 원본 kubeconfig 사용: " + e .getMessage ());
132- e .printStackTrace ();
133- return kubeconfig ;
134- }
135- }
136-
137- /**
138- * kubeconfig에서 cluster ID 추출
139- */
140- private String extractClusterId (String kubeconfig ) {
141- for (String line : kubeconfig .split ("\n " )) {
142- if (line .contains ("/spider/cluster/" ) && line .contains ("/token" )) {
143- // "http://localhost:1024/spider/cluster/CLUSTER_ID/token?ConnectionName=..."
144- String [] parts = line .split ("/spider/cluster/" );
145- if (parts .length > 1 ) {
146- String clusterPart = parts [1 ].split ("/token" )[0 ];
147- return clusterPart ;
148- }
149- }
150- }
151- throw new RuntimeException ("kubeconfig에서 cluster ID를 찾을 수 없습니다" );
152- }
153-
154- /**
155- * kubeconfig에서 connection name 추출
156- */
157- private String extractConnectionName (String kubeconfig ) {
158- for (String line : kubeconfig .split ("\n " )) {
159- if (line .contains ("ConnectionName=" )) {
160- // "http://localhost:1024/spider/cluster/.../token?ConnectionName=CONNECTION_NAME"
161- String [] parts = line .split ("ConnectionName=" );
162- if (parts .length > 1 ) {
163- return parts [1 ].trim ();
164- }
165- }
166- }
167- throw new RuntimeException ("kubeconfig에서 ConnectionName을 찾을 수 없습니다" );
168- }
169-
170- /**
171- * Tumblebug에서 현재 토큰을 가져옵니다 (Java HTTP 클라이언트 사용)
172- */
173- private String getCurrentToken (String clusterId , String connectionName ) throws Exception {
174- // URL 인코딩 처리 (백슬래시 및 따옴표 문제 해결)
175- String cleanConnectionName = connectionName .replace ("\\ " , "" ).replace ("\" " , "" ).trim ();
176- String encodedConnectionName = URLEncoder .encode (cleanConnectionName , StandardCharsets .UTF_8 );
177- String tokenUrl = "http://" + tumblebugUrl + ":1024/spider/cluster/" + clusterId + "/token?ConnectionName=" + encodedConnectionName ;
178-
179- System .out .println ("토큰 요청 URL: " + tokenUrl );
180-
181- // Java HTTP 클라이언트로 토큰 가져오기 (인증 헤더 포함)
182- HttpClient client = HttpClient .newHttpClient ();
183-
184- // Basic Auth 헤더 생성
185- String auth = tumblebugId + ":" + tumblebugPassword ;
186- String encodedAuth = java .util .Base64 .getEncoder ().encodeToString (auth .getBytes ());
187-
188- HttpRequest request = HttpRequest .newBuilder ()
189- .uri (URI .create (tokenUrl ))
190- .header ("Authorization" , "Basic " + encodedAuth )
191- .GET ()
192- .build ();
193-
194- HttpResponse <String > response = client .send (request , HttpResponse .BodyHandlers .ofString ());
195-
196- if (response .statusCode () != 200 ) {
197- throw new RuntimeException ("토큰 요청 실패: HTTP " + response .statusCode () + " - " + response .body ());
198- }
199-
200- String responseBody = response .body ();
201- System .out .println ("Tumblebug 응답: " + responseBody );
202-
203- // JSON 응답에서 token 추출 (더 정확한 파싱)
204- if (responseBody .contains ("\" token\" " )) {
205- // "token":"실제토큰값" 형태에서 토큰 추출
206- int tokenStart = responseBody .indexOf ("\" token\" :\" " ) + 9 ;
207- int tokenEnd = responseBody .indexOf ("\" " , tokenStart );
208- if (tokenStart > 8 && tokenEnd > tokenStart ) {
209- String token = responseBody .substring (tokenStart , tokenEnd );
210- return token ;
211- }
212- }
213-
214- throw new RuntimeException ("토큰을 찾을 수 없습니다: " + responseBody );
215- }
216-
217- /**
218- * kubeconfig에서 exec 플러그인을 제거하고 직접 토큰을 설정
219- */
220- private String replaceExecWithToken (String kubeconfig , String token ) {
221- System .out .println ("=== kubeconfig 수정 시작 ===" );
222-
223- // kubeconfig를 줄별로 분석하여 정확한 YAML 구조 유지
224- String [] lines = kubeconfig .split ("\n " );
225- StringBuilder result = new StringBuilder ();
226- boolean inExecBlock = false ;
227- boolean userBlockFound = false ;
228- boolean tokenAdded = false ;
229-
230- for (int i = 0 ; i < lines .length ; i ++) {
231- String line = lines [i ];
232-
233- if (line .trim ().startsWith ("users:" )) {
234- userBlockFound = true ;
235- result .append (line ).append ("\n " );
236- } else if (userBlockFound && line .trim ().startsWith ("exec:" )) {
237- inExecBlock = true ;
238- System .out .println ("exec 블록 발견, 토큰으로 교체 중..." );
239- // exec: 라인을 token: 라인으로 교체
240- result .append (" token: " ).append (token ).append ("\n " );
241- tokenAdded = true ;
242- // exec 블록의 나머지 라인들 건너뛰기
243- i ++;
244- while (i < lines .length && (lines [i ].startsWith (" " ) || lines [i ].startsWith (" " ))) {
245- i ++;
246- }
247- i --; // 다음 반복에서 현재 라인을 처리하도록
248- } else if (inExecBlock && (line .startsWith (" " ) || line .startsWith (" " ))) {
249- // exec 블록 내부 라인들 건너뛰기
250- continue ;
251- } else if (inExecBlock && !line .startsWith (" " ) && !line .startsWith ("\t " )) {
252- // exec 블록 종료
253- inExecBlock = false ;
254- result .append (line ).append ("\n " );
255- } else {
256- result .append (line ).append ("\n " );
257- }
258- }
259-
260- // 토큰이 추가되지 않았다면 users 섹션에 직접 추가
261- if (!tokenAdded && userBlockFound ) {
262- System .out .println ("exec 블록을 찾을 수 없음, users 섹션에 토큰 추가" );
263- String modifiedKubeconfig = result .toString ();
264- modifiedKubeconfig = modifiedKubeconfig .replace (
265- "users:\n - name: aws-dynamic-token\n user:" ,
266- "users:\n - name: aws-dynamic-token\n user:\n token: " + token
267- );
268- return modifiedKubeconfig ;
269- }
270-
271- System .out .println ("=== kubeconfig 수정 완료 ===" );
272- return result .toString ();
273- }
27461}
0 commit comments