class ZTSClient implements Closeable {

    public AWSLambdaIdentity getAWSLambdaServiceCertificate(String domainName,
            String serviceName, String account, String provider) {
        
        if (domainName == null || serviceName == null) {
            throw new IllegalArgumentException("Domain and Service must be specified");
        }
        
        if (account == null || provider == null) {
            throw new IllegalArgumentException("AWS Account and Provider must be specified");
        }
        
        if (x509CsrDomain == null) {
            throw new IllegalArgumentException("X509 CSR Domain must be specified");
        }
        
        // first we're going to generate a private key for the request
        
        AWSLambdaIdentity lambdaIdentity = new AWSLambdaIdentity();
        try {
            lambdaIdentity.setPrivateKey(Crypto.generateRSAPrivateKey(2048));
        } catch (CryptoException ex) {
            throw new ZTSClientException(ZTSClientException.BAD_REQUEST, ex.getMessage());
        }

        // we need to generate an csr with an instance register object
        
        InstanceRegisterInformation info = new InstanceRegisterInformation();
        info.setDomain(domainName.toLowerCase());
        info.setService(serviceName.toLowerCase());
        info.setProvider(provider.toLowerCase());

        final String athenzService = info.getDomain() + "." + info.getService();
        
        // generate our dn which will be based on our service name

        StringBuilder dnBuilder = new StringBuilder(128);
        dnBuilder.append("cn=");
        dnBuilder.append(athenzService);
        if (x509CsrDn != null) {
            dnBuilder.append(',');
            dnBuilder.append(x509CsrDn);
        }
        
        // now let's generate our dsnName field based on our principal's details

        GeneralName[] sanArray = new GeneralName[3];
        final String hostBuilder = info.getService() + '.' + info.getDomain().replace('.', '-') +
                '.' + x509CsrDomain;
        sanArray[0] = new GeneralName(GeneralName.dNSName, new DERIA5String(hostBuilder));

        final String instanceHostBuilder = "lambda-" + account + '-' + info.getService() +
                ".instanceid.athenz." + x509CsrDomain;
        sanArray[1] = new GeneralName(GeneralName.dNSName, new DERIA5String(instanceHostBuilder));

        final String spiffeUri = "spiffe://" + info.getDomain() + "/sa/" + info.getService();
        sanArray[2] = new GeneralName(GeneralName.uniformResourceIdentifier, new DERIA5String(spiffeUri));

        // next generate the csr based on our private key and data
        
        try {
            info.setCsr(Crypto.generateX509CSR(lambdaIdentity.getPrivateKey(),
                    dnBuilder.toString(), sanArray));
        } catch (OperatorCreationException | IOException ex) {
            throw new ZTSClientException(ZTSClientException.BAD_REQUEST, ex.getMessage());
        }
        
        // finally obtain attestation data for lambda
        
        info.setAttestationData(getAWSLambdaAttestationData(athenzService, account));
        
        // request the x.509 certificate from zts server
        
        Map<String, List<String>> responseHeaders = new HashMap<>();
        InstanceIdentity identity = postInstanceRegisterInformation(info, responseHeaders);
        
        try {
            lambdaIdentity.setX509Certificate(Crypto.loadX509Certificate(identity.getX509Certificate()));
        } catch (CryptoException ex) {
            throw new ZTSClientException(ZTSClientException.BAD_REQUEST, ex.getMessage());
        }

        lambdaIdentity.setCaCertificates(identity.getX509CertificateSigner());
        return lambdaIdentity;
    }

    public  ZTSClient();
    public  ZTSClient(String ztsUrl);
    public  ZTSClient(Principal identity);
    public  ZTSClient(String ztsUrl, Principal identity);
    public  ZTSClient(String ztsUrl, SSLContext sslContext);
    public  ZTSClient(String ztsUrl, String proxyUrl, SSLContext sslContext);
    public  ZTSClient(String domainName, String serviceName, ServiceIdentityProvider siaProvider);
    public  ZTSClient(String ztsUrl, String domainName, String serviceName,
                     ServiceIdentityProvider siaProvider);

}