Skip to content

Commit 8c09446

Browse files
committed
Modify tests, including test setup scripts, and update README
1 parent 51784e5 commit 8c09446

File tree

6 files changed

+226
-2
lines changed

6 files changed

+226
-2
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
build/
2+
tst/certs/
3+
credential-process-data/

README.md

+22-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,28 @@ After building, you should see the `aws_signing_helper` binary built for your sy
1616

1717
There are three commands that are currently implemented within the source code. Two of these commands, `sign-string` and `read-certificate-data` are given as diagnostic tools. The former command allows one to sign a string that comes from standard input. The command requires one to pass in the path of a private key on disk to perform the signing (`--private-key`), as well as two optional arguments for the digest (`--digest`) and output format (`--format`). The digest has to be one of `SHA256`, `SHA384`, and `SHA512` if specified. The default value will be `SHA256` if it isn't specified. The output format has to be one of `text`, `json`, and `bin` if specified. The default value will be `text` if it isn't specified. The latter command allows one to read a certificate that is on disk. The path to the certificate (`--certificate`) is required.
1818

19-
The last command is `credential-process`, which returns temporary credentials in a JSON format that is compatible with the `credential_process` feature available across language SDKs. Documentation on usage, along with examples can be found [here](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html).
19+
The last command is `credential-process`, which returns temporary credentials in a JSON format that is compatible with the `credential_process` feature available across language SDKs. Documentation on usage, along with examples can be found [here](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html). A script called `generate-credential-process-data.sh` can be found at the root of the project, which will generate RSA private keys and their corresponding certificates, that you can use to obtain temporary credentials from IAM Roles Anywhere. You can run the script using `/bin/bash generate-credential-process-data.sh`. Afterwards, you should see the generated private keys and certificates under the `credential-process-data` directory. The following example showcases how to use the data to obtain temporary credentials:
20+
21+
```
22+
TA_ARN=$(aws rolesanywhere create-trust-anchor \
23+
--name "Test TA" \
24+
--source "sourceType=CERTIFICATE_BUNDLE,sourceData={x509CertificateData=$(cat credential-process-data/root-cert.pem)}" \
25+
--enabled | jq -r '.trustAnchor.trustAnchorArn')
26+
27+
PROFILE_ARN=$(aws rolesanywhere create-profile \
28+
--name "Test Profile" \
29+
--role-arns '["<your-role-arn>"]' \
30+
--enabled | jq -r '.profile.profileArn')
31+
32+
/path/to/aws_signing_helper credential-process \
33+
--certificate credential-process-data/client-cert.pem \
34+
--private-key credential-process-data/client-key.pem \
35+
--role-arn <your-role-arn> \
36+
--trust-anchor-arn ${TA_ARN} \
37+
--profile-arn ${PROFILE_ARN}
38+
```
39+
40+
In the above example, you will have to create a role with a trust policy as documented [here](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/trust-model.html). After having done so, record the role ARN and use it both when creating a profile and when obtaining temporary security credentials through `credential-process`.
2041

2142
## Security
2243

aws_signing_helper/signer_test.go

+98-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,41 @@ import (
1414
"errors"
1515
"log"
1616
"net/http"
17+
"net/http/httptest"
18+
"os"
19+
"os/exec"
1720
"strings"
1821
"testing"
1922

2023
"github.com/aws/aws-sdk-go/aws/request"
2124
)
2225

26+
func setup() error {
27+
generateCertsScript := exec.Command("/bin/bash", "../generate-certs.sh")
28+
_, err := generateCertsScript.Output()
29+
if err != nil {
30+
return err
31+
}
32+
33+
generateCredentialProcessDataScript := exec.Command("/bin/bash", "../generate-credential-process-data.sh")
34+
_, err = generateCredentialProcessDataScript.Output()
35+
if err != nil {
36+
return err
37+
}
38+
39+
return nil
40+
}
41+
42+
func TestMain(m *testing.M) {
43+
err := setup()
44+
if err != nil {
45+
log.Println(err.Error())
46+
os.Exit(1)
47+
}
48+
code := m.Run()
49+
os.Exit(code)
50+
}
51+
2352
// Simple struct to define fixtures
2453
type CertData struct {
2554
CertPath string
@@ -30,7 +59,6 @@ type CertData struct {
3059
// if they do not exist, or need to be updated.
3160
func TestReadCertificateData(t *testing.T) {
3261
fixtures := []CertData{
33-
{"../tst/certs/integ-client.pem", "RSA"},
3462
{"../tst/certs/ec-prime256v1-sha256-cert.pem", "EC"},
3563
{"../tst/certs/rsa-2048-sha256-cert.pem", "RSA"},
3664
}
@@ -77,6 +105,7 @@ func TestReadPrivateKeyData(t *testing.T) {
77105
_, err := ReadPrivateKeyData(fixture)
78106

79107
if err != nil {
108+
t.Log(fixture)
80109
t.Log(err)
81110
t.Log("Failed to read private key data")
82111
t.Fail()
@@ -193,3 +222,71 @@ func TestSign(t *testing.T) {
193222
}
194223
}
195224
}
225+
226+
func TestCredentialProcess(t *testing.T) {
227+
testTable := []struct {
228+
name string
229+
server *httptest.Server
230+
}{
231+
{
232+
name: "create-session-server-response",
233+
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
234+
w.WriteHeader(http.StatusCreated)
235+
w.Write([]byte(`{
236+
"credentialSet":[
237+
{
238+
"assumedRoleUser": {
239+
"arn": "arn:aws:sts::000000000000:assumed-role/ExampleS3WriteRole",
240+
"assumedRoleId": "assumedRoleId"
241+
},
242+
"credentials":{
243+
"accessKeyId": "accessKeyId",
244+
"expiration": "2022-07-27T04:36:55Z",
245+
"secretAccessKey": "secretAccessKey",
246+
"sessionToken": "sessionToken"
247+
},
248+
"packedPolicySize": 10,
249+
"roleArn": "arn:aws:iam::000000000000:role/ExampleS3WriteRole",
250+
"sourceIdentity": "sourceIdentity"
251+
}
252+
],
253+
"subjectArn": "arn:aws:rolesanywhere:us-east-1:000000000000:subject/41cl0bae-6783-40d4-ab20-65dc5d922e45"
254+
}`))
255+
})),
256+
},
257+
}
258+
for _, tc := range testTable {
259+
credentialsOpts := CredentialsOpts{
260+
PrivateKeyId: "../credential-process-data/client-key.pem",
261+
CertificateId: "../credential-process-data/client-cert.pem",
262+
RoleArn: "arn:aws:iam::000000000000:role/ExampleS3WriteRole",
263+
ProfileArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:profile/41cl0bae-6783-40d4-ab20-65dc5d922e45",
264+
TrustAnchorArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:trust-anchor/41cl0bae-6783-40d4-ab20-65dc5d922e45",
265+
Endpoint: tc.server.URL,
266+
SessionDuration: 900,
267+
}
268+
t.Run(tc.name, func(t *testing.T) {
269+
defer tc.server.Close()
270+
resp, err := GenerateCredentials(&credentialsOpts)
271+
272+
if err != nil {
273+
t.Log(err)
274+
t.Log("Unable to call credential-process")
275+
t.Fail()
276+
}
277+
278+
if resp.AccessKeyId != "accessKeyId" {
279+
t.Log("Incorrect access key id")
280+
t.Fail()
281+
}
282+
if resp.SecretAccessKey != "secretAccessKey" {
283+
t.Log("Incorrect secret access key")
284+
t.Fail()
285+
}
286+
if resp.SessionToken != "sessionToken" {
287+
t.Log("Incorrect session token")
288+
t.Fail()
289+
}
290+
})
291+
}
292+
}

credential-process-data/.gitkeep

Whitespace-only changes.

generate-certs.sh

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/bin/bash
2+
3+
# Simple script to generate key/digest permutations for testing
4+
# keys are shared across certificates with the same algorithm,
5+
# but different digests
6+
7+
ec_digests="sha1 sha256 sha384 sha512"
8+
ec_curves="prime256v1 secp384r1"
9+
10+
rsa_digests="md5 sha1 sha256 sha384 sha512"
11+
rsa_key_lengths="1024 2048 4096"
12+
13+
script=$(readlink -f "$0")
14+
basedir=$(dirname "$script")
15+
16+
for c in $ec_curves; do
17+
key_file="${basedir}/tst/certs/ec-${c}-key.pem"
18+
openssl ecparam -name $c -genkey -out $key_file
19+
for d in $ec_digests; do
20+
cert_file="${basedir}/tst/certs/ec-${c}-${d}-cert.pem"
21+
openssl req -x509 -new \
22+
-key $key_file \
23+
-out $cert_file \
24+
-days 365 \
25+
-subj "/CN=roles-anywhere-${c}-${d}" \
26+
-${d}
27+
openssl pkcs8 -topk8 -inform PEM -outform PEM \
28+
-in ${basedir}/tst/certs/ec-${c}-key.pem \
29+
-out ${basedir}/tst/certs/ec-${c}-key-pkcs8.pem \
30+
-nocrypt
31+
done;
32+
done;
33+
34+
for l in $rsa_key_lengths; do
35+
key_file="${basedir}/tst/certs/rsa-${l}-key.pem"
36+
openssl genrsa -out $key_file $l
37+
for d in $rsa_digests; do
38+
cert_file="${basedir}/tst/certs/rsa-${l}-${d}-cert.pem"
39+
openssl req -x509 -new \
40+
-key $key_file \
41+
-out $cert_file \
42+
-days 365 \
43+
-subj "/CN=roles-anywhere-rsa-${l}"
44+
openssl pkcs8 -topk8 -inform PEM -outform PEM \
45+
-in ${basedir}/tst/certs/rsa-${l}-key.pem \
46+
-out ${basedir}/tst/certs/rsa-${l}-key-pkcs8.pem \
47+
-nocrypt
48+
done;
49+
done;
50+
51+
# Create certificate bundle
52+
cp ${basedir}/tst/certs/rsa-2048-sha256-cert.pem ${basedir}/tst/certs/cert-bundle.pem
53+
cat ${basedir}/tst/certs/ec-prime256v1-sha256-cert.pem >> ${basedir}/tst/certs/cert-bundle.pem

generate-credential-process-data.sh

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/bash
2+
3+
# Simple script to generate a CA certificate/private key
4+
# and end-entity certificate/private key for use with
5+
# Roles Anywhere
6+
7+
set -exuo pipefail
8+
9+
script=$(readlink -f "$0")
10+
basedir=$(dirname "$script")
11+
data_folder=${basedir}/credential-process-data
12+
13+
# Create root CA config file
14+
cat > ${data_folder}/root.conf << EOF
15+
[ req ]
16+
distinguished_name = req_distinguished_name
17+
prompt = no
18+
19+
[ req_distinguished_name ]
20+
CN = TEST ROOT
21+
22+
[ v3 ]
23+
basicConstraints = critical,CA:TRUE,pathlen:1
24+
subjectKeyIdentifier = hash
25+
keyUsage = critical, cRLSign, digitalSignature, keyCertSign
26+
authorityKeyIdentifier = keyid:always,issuer:always
27+
EOF
28+
29+
# Create root CA certificate and RSA private key
30+
openssl req -config ${data_folder}/root.conf -days 365 -extensions v3 -keyout ${data_folder}/root-key.pem -newkey rsa:2048 -nodes -out ${data_folder}/root-cert.pem -set_serial 1 -sha256 -x509
31+
32+
# Create client certificate config file
33+
cat > ${data_folder}/client.conf <<EOF
34+
[ req ]
35+
distinguished_name = req_distinguished_name
36+
prompt = no
37+
default_bits = 2048
38+
default_md = sha256
39+
40+
[ req_distinguished_name ]
41+
CN = TEST CLIENT
42+
43+
[ v3 ]
44+
authorityKeyIdentifier=keyid,issuer
45+
basicConstraints=CA:FALSE
46+
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
47+
EOF
48+
49+
# Create client certificate and RSA private key
50+
openssl req -nodes -new -keyout ${data_folder}/client-key.pem -out ${data_folder}/client-csr.pem -config ${data_folder}/client.conf
51+
openssl x509 -req -in ${data_folder}/client-csr.pem -CA ${data_folder}/root-cert.pem -CAkey ${data_folder}/root-key.pem -set_serial 2 -out ${data_folder}/client-cert.pem -days 365 -sha256 -extfile ${data_folder}/client.conf -extensions v3

0 commit comments

Comments
 (0)