在jenkins管道中生成AWS 4-HMAC-SHA 256签名时签名不匹配

dauxcl2d  于 2023-04-29  发布在  Jenkins
关注(0)|答案(1)|浏览(248)

我尝试使用Jenkinns管道生成AWS身份验证V4签名,用于访问scaleway云中的S3存储桶,这是我的脚本

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Hex;

def SHA256Hash(String input) {
    // Create a MessageDigest object for SHA-256 hashing
    def digest = MessageDigest.getInstance('SHA-256')
    
    // Convert the input string to bytes and hash it
    def hashedBytes = digest.digest(input.getBytes('UTF-8'))
    
    // Convert the hashed bytes to a hexadecimal string
    def hexString = new StringBuilder()
    hashedBytes.each { b ->
        def hex = Integer.toHexString(0xff & b)
        if (hex.length() == 1) hexString.append('0')
        hexString.append(hex)
    }
    return hexString.toString()
}

def sign(key, msg) {
    SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(keySpec);
    byte[] signatureBytes = mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
    echo "thats from function ${signatureBytes}"
    return Hex.encodeHexString(signatureBytes);
}

pipeline {
    agent any
    environment {
        AWS_ACCESS_KEY_ID = credentials('my-bucket-api-access-key')
        AWS_SECRET_ACCESS_KEY = credentials('my-bucket-api-secret-key')
        AWS_DEFAULT_REGION = 'fr-par'
        SERVICE = 's3'
        S3_BUCKET_NAME = "NAME_OF_BUCKET"
        HOST = "${S3_BUCKET_NAME}.s3.${AWS_DEFAULT_REGION}.scw.cloud"
    }
    stages {
        stage('AWS Version 4 signing') {
            steps {
                script {
                    def date_stamp = new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
                    //generate signing key
                    def signing_key = "AWS4${AWS_SECRET_ACCESS_KEY}"
                    signing_key =sign(sign(sign(sign(signing_key, date_stamp), AWS_DEFAULT_REGION), SERVICE), 'aws4_request')
                    echo " signing_key ${signing_key}"

                    //generate string to sign
                    def method = 'GET'
                    def amz_date = new Date().format("yyyyMMdd'T'HHmmss'Z'", TimeZone.getTimeZone("UTC"))
                    def canonical_uri = '/'
                    def canonical_querystring = ''
                    def Amz_Content_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
                    def payload_hash = Amz_Content_SHA256
                    def canonical_headers = "host:${HOST}\nx-amz-content-sha256:${Amz_Content_SHA256}\nx-amz-date:${amz_date}"
                    def signed_headers = 'host;x-amz-content-sha256;x-amz-date'
                    def canonical_request = "${method}\n${canonical_uri}\n${canonical_querystring}\n${canonical_headers}\n${signed_headers}\n${payload_hash}"
                    echo " canonical_request ${canonical_request}"
                    def algorithm = 'AWS4-HMAC-SHA256'
                    def credential_scope = "${date_stamp}/${AWS_DEFAULT_REGION}/${SERVICE}/aws4_request"
                    def canonicalRequestHash = SHA256Hash(canonical_request)
                    def string_to_sign = "${algorithm}\n${amz_date}\n${credential_scope}\n${canonicalRequestHash}"
                    echo " string_to_sign ${string_to_sign}"

                    //create signature
                    def signature = sign(signing_key, string_to_sign)
                    echo " signature ${signature}"

                    //create authorization header
                    def authorization_header = "${algorithm} Credential=${AWS_ACCESS_KEY_ID}/${credential_scope},SignedHeaders=${signed_headers},Signature=${signature}"
                    echo " authorization_header ${authorization_header}"

                    def s3ListObjectsUrl = "http://${S3_BUCKET_NAME}.s3.${AWS_DEFAULT_REGION}.scw.cloud"
                    def s3Host = "${S3_BUCKET_NAME}.s3.${AWS_DEFAULT_REGION}.scw.cloud"

                    sh """
                        curl -X GET "${s3ListObjectsUrl}" \
                        -H "Host: ${s3Host}" \
                        -H "X-Amz-Content-Sha256: ${Amz_Content_SHA256}" \
                        -H "X-Amz-Date: ${amz_date}" \
                        -H "Authorization: ${authorization_header}"
                    """
                }
            }
        }
    }
}

我得到的签名不匹配响应jenkins response
为了排除故障,我尝试了:
1-检查我的凭据与 Postman 和它的工作postman 200 response
2-检查我的两个函数**SHA 256 Hash(String input)sign(key,msg)**的散列值,并使用在线工具比较HmacSHA 256和SHA 256值,我得到了相同的值
3-我遵循scaleway documentation来验证空格和“\n”
但我总是有同样的问题,我哪里做错了?

vx6bjr1n

vx6bjr1n1#

解决方案:1-修改canonicalHeaderssignedHeaders这两个日志

def canonical_headers = "host:${HOST}\nx-amz-date:${amz_date}\n"
def signed_headers = 'host;x-amz-date'

因此,X-Amz-Content-Sha 256报头仅停留在请求中而不是在签名的****计算
2-修改sign函数(HmacSHA 256哈希函数)

def sign(key, msg) {
    SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(keySpec);
    byte[] signatureBytes = mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
    echo "thats from function ${signatureBytes}"
    return signatureBytes
}

我不遵循的文档,并感谢如何张贴这个解决方案script与python在那里我发现了差异

相关问题