รับโทเค็นการรับรองความถูกต้องจาก AWS EKS โดยใช้ AWS Java SDK v2


11

ฉันจะรับโทเค็นการตรวจสอบสิทธิ์ Kubernetes จาก AWS EKS โดยใช้ AWS Java SDK v2 ได้อย่างไร โทเค็นการรับรองความถูกต้องที่สามารถใช้ในการรับรองความถูกต้องกับ Kubernetes โดยใช้ Kubernetes SDK กล่าวอีกนัยหนึ่งฉันต้องการได้รับโทเค็นการรับรองความถูกต้องจาก EKS เพื่อใช้สำหรับการรับรองความถูกต้องกับ Kubernetes เพื่อที่ฉันจะได้ไม่ต้องสร้าง "kube config"

ที่จริงผมมีวิธีการแก้ปัญหาการทำงานร่วมกับ AWS Java SDK v1 (ไม่ v2) มองไปที่ตัวอย่างโค้ดในต่อไปนี้เปิดประเด็น นอกจากนี้ยังมีตัวอย่างโค้ด Python ที่นี่แต่ฉันไม่ประสบความสำเร็จกับ AWS Java SDK v2 ความพยายามทำด้วย AWS Java SDK v2 ของฉัน:

public static String getAuthenticationToken(AwsCredentialsProvider awsAuth, Region awsRegion, String clusterName) {
    try {
        SdkHttpFullRequest requestToSign = SdkHttpFullRequest
                .builder()
                .method(SdkHttpMethod.GET)
                .uri(new URI("https", String.format("sts.%s.amazonaws.com", awsRegion.id()), null, null))
                .appendHeader("x-k8s-aws-id", clusterName)
                .appendRawQueryParameter("Action", "GetCallerIdentity")
                .appendRawQueryParameter("Version", "2011-06-15")
                .build();

        ZonedDateTime expirationDate = DateUtil.addSeconds(DateUtil.now(), 60);
        Aws4PresignerParams presignerParams = Aws4PresignerParams.builder()
                .awsCredentials(awsAuth.resolveCredentials())
                .expirationTime(expirationDate.toInstant())
                .signingName("sts")
                .signingRegion(awsRegion)
                .build();

        SdkHttpFullRequest signedRequest = Aws4Signer.create().presign(requestToSign, presignerParams);

        String encodedUrl = Base64.getUrlEncoder().withoutPadding().encodeToString(signedRequest.getUri().toString().getBytes(CharSet.UTF_8.getCharset()));
        return ("k8s-aws-v1." + encodedUrl);
    } catch (Exception e) {
        String errorMessage = "A problem occurred generating an Eks token";
        logger.error(errorMessage, e);
        throw new RuntimeException(errorMessage, e);
    }
}

มันสร้างโทเค็น แต่เมื่อฉันใช้โทเค็นในไคลเอนต์ Kubernetes ของฉัน (Java Kubernetes SDK อย่างเป็นทางการ) ฉันได้รับการตอบกลับ "ไม่ได้รับอนุญาต" - ดังนั้นฉันจึงขาดสิ่งที่ฉันไม่สามารถวางนิ้วบน ...

รุ่น AWS Java SDK v1 มีลักษณะดังนี้: (จากปัญหาเปิดที่กล่าวถึงก่อนหน้านี้)

ฉันทำงานได้ แต่ฉันพยายามดิ้นรนเพื่อให้คล้ายกับทำงานใน AWS Java SDK v2

private String generateToken(String clusterName,
                                 Date expirationDate,
                                 String serviceName,
                                 String region,
                                 AWSSecurityTokenServiceClient awsSecurityTokenServiceClient,
                                 AWSCredentialsProvider credentialsProvider,
                                 String scheme,
                                 String host) throws URISyntaxException {
        try {
            DefaultRequest<GetCallerIdentityRequest> callerIdentityRequestDefaultRequest = new DefaultRequest<>(new GetCallerIdentityRequest(), serviceName);
            URI uri = new URI(scheme, host, null, null);
            callerIdentityRequestDefaultRequest.setResourcePath("/");
            callerIdentityRequestDefaultRequest.setEndpoint(uri);
            callerIdentityRequestDefaultRequest.setHttpMethod(HttpMethodName.GET);
            callerIdentityRequestDefaultRequest.addParameter("Action", "GetCallerIdentity");
            callerIdentityRequestDefaultRequest.addParameter("Version", "2011-06-15");
            callerIdentityRequestDefaultRequest.addHeader("x-k8s-aws-id", clusterName);

            Signer signer = SignerFactory.createSigner(SignerFactory.VERSION_FOUR_SIGNER, new SignerParams(serviceName, region));
            SignerProvider signerProvider = new DefaultSignerProvider(awsSecurityTokenServiceClient, signer);
            PresignerParams presignerParams = new PresignerParams(uri,
                    credentialsProvider,
                    signerProvider,
                    SdkClock.STANDARD);

            PresignerFacade presignerFacade = new PresignerFacade(presignerParams);
            URL url = presignerFacade.presign(callerIdentityRequestDefaultRequest, expirationDate);
            String encodedUrl = Base64.getUrlEncoder().withoutPadding().encodeToString(url.toString().getBytes());
            log.info("Token [{}]", encodedUrl);
            return "k8s-aws-v1." + encodedUrl;
        } catch (URISyntaxException e) {
            log.error("could not generate token", e);
            throw e;
        }
    }

ตามที่ระบุในปัญหา AWS Java SDK v1 การใช้งานนั้นมีความละเอียดอ่อนเพื่อระบุวันหมดอายุที่ยาวเกินไป ฉันเล่นรอบกับวันหมดอายุเล็กน้อย แต่ก็ไม่ได้แก้ปัญหา
NS du Toit

คุณลองใช้ยูทิลิตี้ aws-iam-authenticator เพื่อรับโทเค็น
Umesh Kumhar

ฉันเคยใช้ aws-iam-authenticator มาก่อน แต่ฉันต้องสามารถสร้างโทเค็นจากซอร์สโค้ด Java ได้โดยไม่ต้องติดตั้งอะไรเลย และฉันได้รับสิ่งนี้เพื่อทำงานกับ AWS Java SDK v1 เพียงมีปัญหากับ v2 ของ SDK
NS du Toit

ขณะนี้ฉันใช้ AWS Java SDK v1 เพื่อสร้างโทเค็น - แต่ตอนนี้ฉันต้องใช้บน classpath ของฉัน :( ทันทีที่ฉันสามารถหาสิ่งนี้ได้ฉันสามารถ refactor และลบ v1 ของ SDK ออกจากการพึ่งพาของฉัน :)
NS du Toit

คุณกำลังใช้งาน Kubernetes รุ่นใดอยู่ แอพนี้หมายถึงทำงานที่ไหน (อยู่นอกกลุ่มอยู่ด้านใน)
mewa

คำตอบ:


2

ในที่สุดฉันก็ใช้งานได้

รุ่น AWS Java SDK v2:

public static String getAuthenticationToken(AwsCredentialsProvider awsAuth, Region awsRegion, String clusterName) {
    try {    
        SdkHttpFullRequest requestToSign = SdkHttpFullRequest
                .builder()
                .method(SdkHttpMethod.GET)
                .uri(StsUtil.getStsRegionalEndpointUri(awsRegion))
                .appendHeader("x-k8s-aws-id", clusterName)
                .appendRawQueryParameter("Action", "GetCallerIdentity")
                .appendRawQueryParameter("Version", "2011-06-15")
                .build();

        ZonedDateTime expirationDate = DateUtil.addSeconds(DateUtil.now(), 60);
        Aws4PresignerParams presignerParams = Aws4PresignerParams.builder()
                .awsCredentials(awsAuth.resolveCredentials())
                .signingRegion(awsRegion)
                .signingName("sts")
                .signingClockOverride(Clock.systemUTC())
                .expirationTime(expirationDate.toInstant())
                .build();

        SdkHttpFullRequest signedRequest = Aws4Signer.create().presign(requestToSign, presignerParams);

        String encodedUrl = Base64.getUrlEncoder().withoutPadding().encodeToString(signedRequest.getUri().toString().getBytes(CharSet.UTF_8.getCharset()));
        return ("k8s-aws-v1." + encodedUrl);
    } catch (Exception e) {
        String errorMessage = "A problem occurred generating an Eks authentication token for cluster: " + clusterName;
        logger.error(errorMessage, e);
        throw new RuntimeException(errorMessage, e);
    }
}

ปัญหาอยู่ในจุดสิ้นสุดของ STS Uri ของฉัน:

public static URI getStsRegionalEndpointUri(Region awsRegion) {
    try {
        return new URI("https", String.format("sts.%s.amazonaws.com", awsRegion.id()), "/", null);
    } catch (URISyntaxException shouldNotHappen) {
        String errorMessage = "An error occurred creating the STS regional endpoint Uri";
        logger.error(errorMessage, shouldNotHappen);
        throw new RuntimeException(errorMessage, shouldNotHappen);
    }
}

หมายเหตุอาร์กิวเมนต์/ในpath(สาม) สำหรับURIวัตถุ AWS Java SDK v1 เวอร์ชันไม่ได้สร้าง URI เช่นนั้น แต่ระบุที่/อื่น หากฉันพิมพ์ออกมาURIเป็น String ที่ฉันได้รับhttps://sts.eu-west-1.amazonaws.com/ในขณะที่เวอร์ชันดั้งเดิมในคำถามเพิ่งกลับมาhttps://sts.eu-west-1.amazonaws.com

น่าสนใจเพียงพอ - เวอร์ชันดั้งเดิมสร้างโทเค็นด้วยเช่นกัน แต่โทเค็นถูกปฏิเสธโดย Kubernetes หนึ่งควรคาดหวังพฤติกรรมที่คล้ายกันหากวันหมดอายุอยู่ไกลเกินไปในอนาคต - คุณจะได้รับโทเค็น แต่มันจะนำไปสู่การUnauthorizedตอบสนองจากบริการ Kubernetes

หลังจากเปลี่ยนจุดสิ้นสุด STS ทุกอย่างทำงานได้ แต่ฉันทำการเปลี่ยนแปลงอีกครั้ง:

ฉันเพิ่มบรรทัดต่อไปนี้ในAws4PresignerParams:

.signingClockOverride(Clock.systemUTC())

ไม่จำเป็น แต่ AWS Java SDK v1 ดั้งเดิมนั้นทำบางอย่างกับนาฬิกาเมื่อมีการระบุSdkClock.STANDARDและZonedDateTimeที่ฉันใช้ในรุ่น AWS Java SDK v2 จะใช้เขตเวลา UTC


ใช่ฉันทำให้มันทำงานได้ แต่ฉันไม่มีความเข้าใจอย่างถ่องแท้เกี่ยวกับเหตุผลที่อยู่เบื้องหลัง แม้จะไม่มี/ฉันก็ยังมีโทเค็น แต่ตามที่ระบุไว้มันก็ไม่ทำงานเมื่อฉันเริ่มทำงานร่วมกับ Kubernetes
NS du Toit

อีกเรื่องที่น่าสนใจ - ปัญหา AWS Java SDK v1 ดั้งเดิมบ่งชี้ว่าโทเค็นมีอายุสั้นมาก ทันทีที่ฉันพยายามกำหนดวันหมดอายุเป็นมากกว่า 60 วินาทีสิ่งเดียวกันก็เกิดขึ้น - ฉันได้รับโทเค็น แต่มันนำไปสู่การUnauthorizedตอบกลับ
NS du Toit
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.