ACMESharp-AWS/ACMESharp-AWS.psm1


#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