ACMESharp-AWS/ACMESharp-AWS.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

#cd C:\prj\letsencrypt\solutions\letsencrypt-win\letsencrypt-win\LetsEncrypt.ACME.POSH
#Add-Type -Path .\bin\Debug\ACMESharp.POSH.dll

<#
Configure/install certs

Install-ACMECertificateToAWS -Ref <cert-ref>
 -IAMPath <path> - optional, prefix with /cloudfront/ to use with CloudFront
 -IAMName <path> - required
 -ELBName <elb-name> - optional to install on ELB
 -ELBPort <elb-port> - required if elb-name is specified
 -VaultProfile <vp>
#>


## We need the AWS POSH Module
Import-Module AWSPowerShell

## TODO: We'll need to either "assume" that the user has
## already imported the module or explicitly re-import it
## and we'll also have to address the Default Noun Prefix
##Import-Module ACMESharp

function Install-CertificateToAWS {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Certificate,
        [Parameter(Mandatory=$true)]
        [string]$IAMName,
        [string]$IAMPath,
        [switch]$UseWithCloudFront,
        [switch]$IAMReplace,
        [string]$ELBName,
        [int]$ELBPort,

        ## AWS POSH Base Params
        [object]$Region,
        [string]$AccessKey,
        [string]$SecretKey,
        [string]$SessionToken,
        [string]$ProfileName,
        [string]$ProfilesLocation,
        [Amazon.Runtime.AWSCredentials]$Credentials
    )

    $vpParams = @{}
    if ($VaultProfile) {
        $vpParams.VaultProfile = $VaultProfile
    }

    ## This switch is just a flag that we need to check for the IAM Server
    ## Certificate path to match some specific naming convention
    if ($UseWithCloudFront) {
        if (-not $IAMPath.StartsWith('/cloudfront/')) {
            throw "IAM Server Certificate path must start with '/cloudfront/' to use with CloudFront"
        }
    }

    $ci = Get-ACMECertificate @vpParams -Ref $Certificate
    if ($ci.IssuerSerialNumber) {
        $ic = Get-ACMEIssuerCertificate @vpParams -SerialNumber $ci.IssuerSerialNumber
        if ($ic) {
            if (-not $ic.CrtPemFile) {
                throw "Unable to resolve Issuer Certificate PEM file"
            }
        }
    }

    if (-not $ci.KeyPemFile) {
        throw "Unable to resolve Private Key PEM file"
    }
    if (-not $ci.CrtPemFile) {
        throw "Unable to resolve Certificate PEM file"
    }

    $privKeyFile = [System.IO.Path]::GetTempFileName()
    $certBodyFile = [System.IO.Path]::GetTempFileName()

    Get-ACMECertificate @vpParams    -Ref $Certificate `
            -ExportKeyPEM $privKeyFile `
            -ExportCertificatePEM $certBodyFile

    $privKey = [System.IO.File]::ReadAllText($privKeyFile)
    $certBody = [System.IO.File]::ReadAllText($certBodyFile)
    if ($ic) {
        $certChainFile = [System.IO.Path]::GetTempFileName()
        Get-ACMEIssuerCertificate @vpParams -ExportCertificatePEM $certChainFile
        $certChain = [System.IO.File]::ReadAllText($certChainFile)
        del $certChainFile
    }
    del $privKeyFile
    del $certBodyFile


    ## Assemble AWS POSH Base Args to pass along for authentication
    $awsBaseArgs = @{
        Region = $Region
        AccessKey = $AccessKey
        SecretKey = $SecretKey
        SessionToken = $SessionToken
        ProfileName = $ProfileName
        ProfilesLocation = $ProfilesLocation
        Credentials = $Credentials
    }

    ## -Certificate 1 -Verbose -ProfileName auto@aws3 -IAMName le1
    ## -Certificate 1 -Verbose -ProfileName auto@aws3 -IAMName le2 -ELBName foo
    ## -Certificate 1 -Verbose -ProfileName auto@aws3 -IAMName le2 -ELBName foo -ELBPort 8443 -Region us-east-1
    ## -Certificate 1 -Verbose -ProfileName auto@aws3 -IAMName le2 -ELBName STAGE-PP-MTB -ELBPort 8443 -Region us-east-1

    $awsCert = $null
    $awsCertMeta = $null
    if ($IAMName) {
        try {
            ## See if a cert for that name already exists
            $awsCert = Get-IAMServerCertificate -ServerCertificateName $IAMName -ErrorAction Ignore @awsBaseArgs
            if ($awsCert) {
                $awsCertMeta = $awsCert.ServerCertificateMetadata
            }
        } catch { }

        if ($awsCertMeta) {
            if ($IAMReplace) {
                Remove-IAMServerCertificate -ServerCertificateName $IAMName -Force @awsBaseArgs
                $awsCert = $null
                $awsCertMeta = $null
            }
            elseif ($awsCert.CertificateBody.Trim() -ne $certBody.Trim()) {
                throw "Non-matching certificate already installed under referenced Server Certificate Name"
            }
            else {
                Write-Verbose "Matching certificate already installed under referenced Server Certificate Name"
            }
        }

        if (-not $awsCertMeta -or $IAMReplace) {
            $apiArgs = @{
                PrivateKey = $privKey
                CertificateBody = $certBody
                CertificateChain = $certChain
                ServerCertificateName = $IAMName
            }
            if ($IAMPath) {
                $apiArgs.Path = $IAMPath
            }
            $awsCertMeta = Publish-IAMServerCertificate @apiArgs @awsBaseArgs
        }
    }

    if ($ELBName) {
        if (-not $ELBPort -or $ELBPort -lt 1) {
            throw "Invalid or missing ELB port"
        }

        $apiArgs = @{
            LoadBalancerName = $ELBName
            LoadBalancerPort = $ELBPort
            SSLCertificateId = $awsCertMeta.Arn
        }
        echo "SSLCertificate = $($awsCert)"
        echo "SSLCertificateM = $($awsCertMeta)"
        echo "SSLCertificateId = $($awsCertMeta.Arn)"
        Set-ELBLoadBalancerListenerSSLCertificate @apiArgs @awsBaseArgs
    }
}

Export-ModuleMember -Function Install-CertificateToAWS