If you do, or want to, use AWS to deploy your apps, you will end up using AWS SES via SMTP when you're launching an app that sends out emails of any kind (user registrations, email notifications, etc). For example, I have used this configuration on various Ruby on Rails apps, however, it is just basic SMTP configurations and crosses over to any framework that supports SMTP sendmail.
There are two ways to go about this:
- EASY WAY: Create an SMTP user via AWS SES [http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html#smtp-credentials-console]
- NOT SO EASY WAY: Create an SMTP password for an existing IAM user [^^ Same link scroll down]
Luckily, you found this MD file and the NOT SO EASY WAY is suddenly copy-pasta... sudo yum....
Assuming you've already set up your SES Policy on your IAM User:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect":"Allow",
"Action":["ses:SendEmail", "ses:SendRawEmail"],
"Resource":"*"
}
]
}
Go ahead and drop this into an bash session, or somewhere in your app, and pass in your IAM user's secret key to generate your SMTP password :)
Thanks @talreg and @cristim and @jschroed91
require 'openssl'
require 'base64'
def aws_iam_smtp_password_generator(key, region)
# The values of the following variables should always stay the same.
date = "11111111"
service = "ses"
terminal = "aws4_request"
message = "SendRawEmail"
version_in_bytes = "\x04"
k_date = OpenSSL::HMAC.digest('sha256', "AWS4" + key, date)
k_region = OpenSSL::HMAC.digest('sha256', k_date, region)
k_service = OpenSSL::HMAC.digest('sha256', k_region, service)
k_terminal = OpenSSL::HMAC.digest('sha256', k_service, terminal)
k_message = OpenSSL::HMAC.digest('sha256', k_terminal, message)
signature_and_version = version_in_bytes + k_message
smtp_password = Base64.encode64(signature_and_version)
smtp_password.to_s.strip
end
# print aws_iam_smtp_password_generator(ENV['AWS_SECRET_ACCESS_KEY'], "us-east-1")
<?php
function aws_iam_smtp_password_generator($secret) {
$message = "SendRawEmail";
$versionInBytes = chr(2);
$signatureInBytes = hash_hmac('sha256', $message, $secret, true);
$signatureAndVer = $versionInBytes.$signatureInBytes;
$smtpPassword = base64_encode($signatureAndVer);
return $smtpPassword;
}
?>
Thanks to @avdhoot and @techsolx
# v2
import base64
import hmac
import hashlib
import sys
def hash_smtp_pass_from_secret_key(key):
message = "SendRawEmail"
version = '\x02'
h = hmac.new(key, message, digestmod=hashlib.sha256)
return base64.b64encode("{0}{1}".format(version, h.digest()))
if __name__ == "__main__":
print hash_smtp_pass_from_secret_key(sys.argv[1])
#####################
# v3
import argparse
import base64
import hashlib
import hmac
def hash_iam_secret(sakey, version):
key_bytes = str.encode(sakey)
message_bytes = str.encode('SendRawEmail')
version_bytes = str.encode(version)
dig = hmac.new(key_bytes, message_bytes, digestmod=hashlib.sha256)
return base64.b64encode(version_bytes+dig.digest()).decode()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('iam_secret_access_key',
type=str,
help='The AWS IAM secret access key')
parser.add_argument('version',
type=str,
nargs='?',
default='\0x2',
help='Optional version number, default is 2')
args = parser.parse_args()
if len(args.iam_secret_access_key) != 40:
print('AWS secret access keys should be 40 characters.')
else:
dig = hash_iam_secret(args.iam_secret_access_key,
args.version)
print(dig)
if __name__ == '__main__':
main()
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
)
const (
awsDate string = "11111111"
awsService string = "ses"
awsMessage string = "SendRawEmail"
awsTerminal string = "aws4_request"
awsVersion byte = 0x04
)
func DeriveSMTPCredential(region, secretKey string) string {
signature := sign([]byte("AWS4"+secretKey), []byte(awsDate))
signature = sign(signature, []byte(region))
signature = sign(signature, []byte(awsService))
signature = sign(signature, []byte(awsTerminal))
signature = sign(signature, []byte(awsMessage))
infoWithSignature := make([]byte, 1+len(signature))
infoWithSignature[0] = awsVersion
copy(infoWithSignature[1:], signature)
return base64.StdEncoding.EncodeToString(infoWithSignature)
}
func sign(key, msg []byte) []byte {
h := hmac.New(sha256.New, key)
h.Write(msg)
return h.Sum(nil)
}
https://gist.github.com/jacqueskang/96c444ee01e6a4b37300aa49e8097513
$key = "${SecretAccessKey}";
$region = "${AWS::Region}";
$date = "11111111";
$service = "ses";
$terminal = "aws4_request";
$message = "SendRawEmail";
$versionInBytes = 0x04;
function HmacSha256($text, $key2) {
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = $key2;
$hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($text));
}
$signature = [Text.Encoding]::UTF8.GetBytes("AWS4" + $key)
$signature = HmacSha256 "$date" $signature;
$signature = HmacSha256 "$region" $signature;
$signature = HmacSha256 "$service" $signature;
$signature = HmacSha256 "$terminal" $signature;
$signature = HmacSha256 "$message" $signature;
$signatureAndVersion = [System.Byte[]]::CreateInstance([System.Byte], $signature.Length + 1);
$signatureAndVersion[0] = $versionInBytes;
$signature.CopyTo($signatureAndVersion, 1);
$smtpPassword = [Convert]::ToBase64String($signatureAndVersion);
Write-Host $smtpPassword;
#!/usr/bin/env escript
%% -*- erlang -*-
-define(DATE , <<"11111111">> ).
-define(SERVICE , <<"ses">> ).
-define(MESSAGE , <<"SendRawEmail">>).
-define(TERMINAL, <<"aws4_request">>).
-define(VERSION , 4 ).
main([Key,Region]) ->
KeyBinary = list_to_binary(Key),
RegionBinary = list_to_binary(Region),
Sig1 = sign(<<"AWS4", KeyBinary/binary>>,?DATE),
Sig2 = sign(Sig1,RegionBinary),
Sig3 = sign(Sig2, ?SERVICE),
Sig4 = sign(Sig3, ?TERMINAL),
Sig5 = sign(Sig4, ?MESSAGE),
SignatureAndVersion = << ?VERSION,Sig5/binary>>,
HB = base64:encode(SignatureAndVersion),
io:format("~s\n",[HB]);
main(_) ->
usage().
sign(Key,Msg) ->
crypto:mac(hmac,sha256,Key,Msg).
usage() ->
io:format("usage: ~p secret_access_key region\n",[escript:script_name()]),
halt(1).
I'm not a Java programmer, yet, but AWS's documentation [http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html#smtp-credentials-convert] has a snippet you can use
I spent way too much time figuring this stuff out. I hope this helps!!!
Thanks, this saved me from spending a lot of time trying to compile that Java code, which is really a mess if you're not a Java developer.
Small suggestion: please just package the Ruby version as a stand-alone script and make it read the secret key from the environment, to do that I just appended this to it: