[AWS 실험] 7 - STS:AssumeRole with AWS SDK

1. AssumeRole이란 무엇입니까?



"Returns a set of temporary security credentials that you can use to access AWS resources that you might not normally have access to. These temporary credentials consist of an access key ID, a secret access key, and a security token." (Amazon Web Services)



2. 하지만 왜 우리는 그것을 사용하고 싶어할까요?



요청 프로세스 중에 클라이언트의 모든 요청을 캡처할 수 있습니다. 예를 들어 GET 요청을 수행할 때 URL 쿼리에 대한 자격 증명을 포함하고 URL에 액세스할 수 있는 사람은 누구나 자격 증명을 훔칠 수 있습니다.
AssumeRole를 사용하여 특정 역할에 대한 임시 자격 증명을 가져오는 것은 자격 증명을 보호하려는 경우에 유용합니다. 따라서 곧 만료되는 임시 자격 증명을 생성하여 자격 증명이 다른 사람에 의해 캡처되더라도 자격 증명이 만료되기 전에 콘텐츠에 액세스할 수 있는 시간이 약간만 있도록 하는 것이 훨씬 더 안전합니다.

임시 자격 증명을 사용하는 것은 단순히 액세스 토큰 및 새로 고침 토큰을 사용하는 것과 동일한 개념입니다. 그러나 AssumeRole API가 매우 다른 점은 IAM 사용자가 사용자가 현재 가지고 있는 것보다 많거나 다른 권한을 가진 "다른 역할"의 임시 자격 증명을 얻을 수 있다는 것입니다.



3. 실험



자원


  • GitHub Repo
  • STS:AssumeRole

  • 전제 조건


  • STS:AssumeRole 권한이 있는 IAM 사용자입니다. 리소스는 사용자가 맡으려는 역할의 일부여야 합니다.
  • 사용자가 맡으려는 IAM 역할입니다. 역할이 현재 사용자에게 없는 권한을 갖는 것이 이상적입니다. 역할은 신뢰할 수 있는 엔터티 중 하나로 사용자를 포함해야 합니다.
  • 사용자가 수행할 수 있도록 허용하려는 모든 AWS 서비스. AWS S3를 사용했습니다.

  • 백엔드 코드



    S3에서 항목 가져오기

    router.get("/item", (req, res) => {
        if (req.query === undefined) 
            return res.json({error:"Invalid QueryStrings"});
    
        const { bucket, key, region } = req.query;
        if (bucket === undefined || region === undefined || key === undefined) 
            return res.json({error:"Invalid QueryStrings"});
    
        // STS AssumeRole token
        sts.assumeRole(stsParams, async function(error, data) {
             if (error) return res.status(error.statusCode).json({error:error.message});
             else{
                try { 
                    const { Credentials: { AccessKeyId, SecretAccessKey, SessionToken } } = data;
                    const bucketParams = {
                        Bucket: bucket
                    }
                    const getObjectParams = {
                        Bucket: bucket, // The name of the bucket. For example, 'sample_bucket_101'.
                        Key: key
                    };
                    const credentials = {
                        accessKeyId: AccessKeyId,
                        secretAccessKey: SecretAccessKey,
                        sessionToken: SessionToken
                    };
                    let s3Client = new S3Client({ region, credentials });
    
                    // Check
                    await doesExistBucketOrObject({s3Client, bucketParams, objectParams:getObjectParams});
    
                    // Returning Pre-signed URL
                    const getObjCommand = new GetObjectCommand(getObjectParams);
                    const url = await getSignedUrl(s3Client, getObjCommand, { expiresIn: 2400 });
                    return res.json({url, success:true});
    
                } catch (error) {
                    return res.status(error.statusCode).json({error, success:false});
                }
            }
        });
    });
    


    multer & S3를 사용하여 파일 업로드

    const upload = multer({ dest: 'uploads/' });
    
    router.post("/item", upload.single("files"),(req, res) => {
        if (req.body === undefined || req.body === null) 
        return res.json({error:"Invalid QueryParameters: req.body"});
    
        const { bucket, key, region } = req.body;
        if (bucket === undefined || region === undefined || key === undefined) 
            return res.json({error:"Invalid QueryParameters"});
        if (req.file === undefined)
            return res.json({error:"No file attached"})
    
        const { filename, path:filepath } = req.file;
        console.log(filename, filepath);
        const realpath = path.join(__dirname.split("src")[0], filepath);
        const realfile = fs.readFileSync(realpath);
        // STS AssumeRole token
        sts.assumeRole(stsParams, async function(error, data) {
            if (error) return res.status(error.statusCode).json({error:error.message});
            else{
                try{
    
                    // STS
                    const { Credentials: { AccessKeyId, SecretAccessKey, SessionToken } } = data;
                    const credentials = {
                        accessKeyId: AccessKeyId,
                        secretAccessKey: SecretAccessKey,
                        sessionToken: SessionToken
                    };
    
                    const putObjectParams = { 
                        Bucket: bucket, 
                        Key: key
                    }
    
                    let s3Client = new S3Client({ region, credentials });
                    const putObjectCommand = new PutObjectCommand(putObjectParams);
                    const signedUrl = await getSignedUrl(s3Client, putObjectCommand, { expiresIn: 2400 })
                        .catch(err => {throw err});
                    const response = await fetch(signedUrl, {method: 'PUT', body: realfile})
                        .catch(err => {throw err;});
                    console.log("Successfully uploaded the object");
                    return res.status(response.status).json({success:true})
                } catch(error) {
                    return res.json({error})
                }
            }
        });
    });
    


    보시다시피 저는 AWS 자격 증명을 사용하여 S3와 직접 상호 작용하지 않았습니다. 대신 먼저 STS에서 임시 자격 증명을 얻은 다음 자격 증명으로 S3와 상호 작용하여 미리 서명된 URL을 수행GetObject하고 버킷 하나PutObject를 수행했습니다.

    좋은 웹페이지 즐겨찾기