我无法弄清楚如何使用Node JS SDK中的KMS加密将文件上传到AWS S3。我一直收到403:拒绝访问错误。我可以使用KMS从AWS S3获取文件。
我正在重复使用https://github.com/gilt/node-s3-encryption-client
中的大部分代码var fs = require('fs'),
AWS = require('aws-sdk'),
crypt = require("./crypt"),
kms,
s3;
const metadataCipherAlgorithm = 'cipher-algorithm',
metadataDecryptedEncoding = 'decrypted-encoding'
metadataKmsKeyName = 'x-amz-key';
/**
* Constructor - Initializes S3 sdk connection
*/
function S3FileStreamer(key, secret, region) {
if (region) {
AWS.config.region = region;
}
//set credentials if passed in
if (key && secret) {
AWS.config.update({accessKeyId: key, secretAccessKey: secret})
}
s3 = new AWS.S3({signatureVersion: "v4"});
kms = new AWS.KMS({apiVersion: '2014-11-01'});
}
S3FileStreamer.prototype.uploadFile = function(bucket, key, kmsKey, filename, onComplete) {
var params = {
Bucket: bucket,
Key: key,
Body: fs.readFileSync(filename),
ContentType: getMimeType(filename)
};
params.KmsParams = {
KeyId: kmsKey,
KeySpec: 'AES_256'
}
kmsUpload(params, function(err, data) {
if (err) onComplete(err, null);
else {
onComplete(err, data);
}
});
};
function kmsUpload(params, callback) {
var kmsParams = params.KmsParams
if (kmsParams && kmsParams.KeyId) {
kms.generateDataKey(kmsParams, function(err, kmsData) {
if (err) {
callback(err, null);
} else {
var helper = new crypt.Helper(kmsData.Plaintext.toString('base64'), {algorithm: params.CipherAlgorithm, decryptedEncoding: params.DecryptedEncoding});
params.Body = helper.encrypt(params.Body);
params.Metadata = params.Metadata || {};
params.Metadata[metadataKmsKeyName] = kmsData.CiphertextBlob.toString('base64');
if (params.CipherAlgorithm) params.Metadata[metadataCipherAlgorithm] = params.CipherAlgorithm;
if (params.DecryptedEncoding) params.Metadata[metadataDecryptedEncoding] = params.DecryptedEncoding;
putObject(params, callback);
}
})
} else {
putObject(params, callback);
}
}
function putObject(params, callback) {
delete params.KmsParams;
delete params.CipherAlgorithm;
delete params.DecryptedEncoding;
s3.putObject(params, callback);
}
var crypto = require('crypto');
/*
options:
algorithm: Anything from crypto.getCiphers()
decryptedEncoding: 'utf8', 'ascii', or 'binary'
outputEncoding: 'binary', 'base64', or 'hex'
*/
exports.Helper = function(password, options) {
this.password = password;
options = options || {};
this.algorithm = options.algorithm || 'aes-256-cbc';
this.decryptedEncoding = options.decryptedEncoding || 'utf8';
this.encryptedEncoding = options.encryptedEncoding || 'base64';
}
exports.Helper.prototype.encrypt = function(unencrypted) {
var cipher = crypto.createCipher(this.algorithm, this.password);
return cipher.update(unencrypted, this.decryptedEncoding, this.encryptedEncoding) + cipher.final(this.encryptedEncoding);
}
exports.Helper.prototype.decrypt = function(encrypted) {
var decipher = crypto.createDecipher(this.algorithm, this.password);
return decipher.update(encrypted, this.encryptedEncoding, this.decryptedEncoding) + decipher.final(this.decryptedEncoding);
}
这里是否有我遗漏的东西,需要设置一个额外的元数据标签?
传递给kms generateDataKey
方法的keyId参数是否应该采用某种独特的格式?我只是简单地传递我的钥匙。
答案 0 :(得分:1)
虽然关于检查权限的另一个答案无疑是正确的。我很难找到一个如何使用AES GCM加密算法解码S3对象的好例子。我设法让这个代码基于aws ruby sdk工作(因为我发现node-s3-encryption-client有点旧)。
/**
* Decrypt s3 file data
* @param {object} objectData result of s3 get call
* @param {Function} callback function(err, data) returns error or decrypted data
*/
function decrypt(objectData, callback) {
var metadata = objectData.Metadata || {};
var kmsKeyBase64 = metadata['x-amz-key-v2'];
var iv = metadata['x-amz-iv'];
var tagLen = (metadata['x-amz-tag-len'] || 0)/8;
var algo = metadata['x-amz-cek-alg'];
var encryptionContext = JSON.parse(metadata['x-amz-matdesc']);
switch (algo) {
case 'AES/GCM/NoPadding':
algo = 'aes-256-gcm';
break;
case 'AES/CBC/PKCS5Padding':
algo = 'aes-256-cbc';
break;
default:
callback(new Error('Unsupported algorithm: ' + algo), null);
return;
}
if (typeof (kmsKeyBase64) === 'undefined') {
callback(new Error('Missing key in metadata'), null);
return;
}
var kmsKeyBuffer = new Buffer(kmsKeyBase64, 'base64');
kms.decrypt({
CiphertextBlob: kmsKeyBuffer,
EncryptionContext: encryptionContext
}, function(err, kmsData) {
if (err) {
callback(err, null);
} else {
var decipher = crypto.createDecipheriv(algo,
kmsData.Plaintext,
new Buffer(iv, 'base64'));
if (tagLen !== 0) {
// the tag is appended to the data buffer
var tag = objectData.Body.slice(-tagLen);
decipher.setAuthTag(tag);
}
var data = objectData.Body.slice(0,-tagLen);
var dec = decipher.update(data, 'binary', 'utf8');
dec += decipher.final('utf8');
console.log("Decoded:", dec);
callback(null, dec);
}
});
}
答案 1 :(得分:0)
感谢所有帮助。我想出了我的问题的解决方案。
我回去使用aws-sdk节点模块,并从node-s3-encryption-client模块中获取了所有代码。
为了使用KMS加密将文件成功上传到Amazon S3,我需要做的就是在将params对象传递给putObject方法之前添加两个参数。这些参数为ServerSideEncryption
和SSEKMSKeyId
,如下所示。它现在有效!
var params = {
Bucket: bucket,
Key: key,
Body: fs.readFileSync(filename),
ContentType: getMimeType(filename),
ServerSideEncryption: 'aws:kms',
SSEKMSKeyId: kmsKey
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
});