Connexion à votre instance de base de données à l'aide de l'authentification IAM et de AWS SDK for Java - Amazon Relational Database Service

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Connexion à votre instance de base de données à l'aide de l'authentification IAM et de AWS SDK for Java

Vous pouvez vous connecter à une instance de base de données RDS pour MariaDB, MySQL ou PostgreSQL avec l'AWS SDK for Java, comme décrit ci-après.

Prérequis

Les conditions préalables à la connexion à votre instance de base de données à l'aide de l'authentification IAM sont les suivantes :

Création d'un jeton d'authentification IAM

Si vous écrivez des programmes à l'aide de AWS SDK for Java, vous pouvez obtenir un jeton d'authentification signé au moyen de la classe RdsIamAuthTokenGenerator. L'usage de cette classe exige que vous fournissiez les informations d'identification AWS. Pour ce faire, vous devez créer une instance de la classe DefaultAWSCredentialsProviderChain. DefaultAWSCredentialsProviderChain utilise la première clé d'accès AWS et la clé secrète trouvée dans la chaîne de fournisseur d'informations d'identification par défaut. Pour plus d'informations sur les clés d'accès AWS, consultez Gestion des clés d'accès pour les utilisateurs IAM.

Note

Vous ne pouvez pas utiliser un enregistrement DNS Route 53 personnalisé à la place du point de terminaison de l'instance de base de données pour générer le jeton d'authentification.

Après avoir créé une instance de RdsIamAuthTokenGenerator, vous pouvez appeler la méthode getAuthToken pour obtenir un jeton signé. Fournissez la région AWS, le nom d'hôte, le numéro de port et le nom d'utilisateur. L'exemple de code suivant montre comment procéder.

package com.amazonaws.codesamples; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.services.rds.auth.GetIamAuthTokenRequest; import com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator; public class GenerateRDSAuthToken { public static void main(String[] args) { String region = "us-west-2"; String hostname = "rdsmysql.123456789012.us-west-2.rds.amazonaws.com"; String port = "3306"; String username = "jane_doe"; System.out.println(generateAuthToken(region, hostname, port, username)); } static String generateAuthToken(String region, String hostName, String port, String username) { RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder() .credentials(new DefaultAWSCredentialsProviderChain()) .region(region) .build(); String authToken = generator.getAuthToken( GetIamAuthTokenRequest.builder() .hostname(hostName) .port(Integer.parseInt(port)) .userName(username) .build()); return authToken; } }

Construction manuelle d'un jeton d'authentification IAM

Dans Java, la manière la plus facile de créer un jeton d'authentification est d'utiliser RdsIamAuthTokenGenerator. Cette classe créé un jeton d'authentification pour vous, puis le signe à l'aide d'AWS Signature Version 4. Pour de plus amples informations, veuillez consulter Processus de signature Signature Version 4 dans le Références générales AWS.

Vous pouvez néanmoins aussi construire et signer un jeton d'authentification manuellement, comme indiqué dans l'exemple de code suivant.

package com.amazonaws.codesamples; import com.amazonaws.SdkClientException; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.auth.SigningAlgorithm; import com.amazonaws.util.BinaryUtils; import org.apache.commons.lang3.StringUtils; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.Charset; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.Date; import java.util.SortedMap; import java.util.TreeMap; import static com.amazonaws.auth.internal.SignerConstants.AWS4_TERMINATOR; import static com.amazonaws.util.StringUtils.UTF8; public class CreateRDSAuthTokenManually { public static String httpMethod = "GET"; public static String action = "connect"; public static String canonicalURIParameter = "/"; public static SortedMap<String, String> canonicalQueryParameters = new TreeMap(); public static String payload = StringUtils.EMPTY; public static String signedHeader = "host"; public static String algorithm = "AWS4-HMAC-SHA256"; public static String serviceName = "rds-db"; public static String requestWithoutSignature; public static void main(String[] args) throws Exception { String region = "us-west-2"; String instanceName = "rdsmysql.123456789012.us-west-2.rds.amazonaws.com"; String port = "3306"; String username = "jane_doe"; Date now = new Date(); String date = new SimpleDateFormat("yyyyMMdd").format(now); String dateTimeStamp = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'").format(now); DefaultAWSCredentialsProviderChain creds = new DefaultAWSCredentialsProviderChain(); String awsAccessKey = creds.getCredentials().getAWSAccessKeyId(); String awsSecretKey = creds.getCredentials().getAWSSecretKey(); String expiryMinutes = "900"; System.out.println("Step 1: Create a canonical request:"); String canonicalString = createCanonicalString(username, awsAccessKey, date, dateTimeStamp, region, expiryMinutes, instanceName, port); System.out.println(canonicalString); System.out.println(); System.out.println("Step 2: Create a string to sign:"); String stringToSign = createStringToSign(dateTimeStamp, canonicalString, awsAccessKey, date, region); System.out.println(stringToSign); System.out.println(); System.out.println("Step 3: Calculate the signature:"); String signature = BinaryUtils.toHex(calculateSignature(stringToSign, newSigningKey(awsSecretKey, date, region, serviceName))); System.out.println(signature); System.out.println(); System.out.println("Step 4: Add the signing info to the request"); System.out.println(appendSignature(signature)); System.out.println(); } //Step 1: Create a canonical request date should be in format YYYYMMDD and dateTime should be in format YYYYMMDDTHHMMSSZ public static String createCanonicalString(String user, String accessKey, String date, String dateTime, String region, String expiryPeriod, String hostName, String port) throws Exception { canonicalQueryParameters.put("Action", action); canonicalQueryParameters.put("DBUser", user); canonicalQueryParameters.put("X-Amz-Algorithm", "AWS4-HMAC-SHA256"); canonicalQueryParameters.put("X-Amz-Credential", accessKey + "%2F" + date + "%2F" + region + "%2F" + serviceName + "%2Faws4_request"); canonicalQueryParameters.put("X-Amz-Date", dateTime); canonicalQueryParameters.put("X-Amz-Expires", expiryPeriod); canonicalQueryParameters.put("X-Amz-SignedHeaders", signedHeader); String canonicalQueryString = ""; while(!canonicalQueryParameters.isEmpty()) { String currentQueryParameter = canonicalQueryParameters.firstKey(); String currentQueryParameterValue = canonicalQueryParameters.remove(currentQueryParameter); canonicalQueryString = canonicalQueryString + currentQueryParameter + "=" + currentQueryParameterValue; if (!currentQueryParameter.equals("X-Amz-SignedHeaders")) { canonicalQueryString += "&"; } } String canonicalHeaders = "host:" + hostName + ":" + port + '\n'; requestWithoutSignature = hostName + ":" + port + "/?" + canonicalQueryString; String hashedPayload = BinaryUtils.toHex(hash(payload)); return httpMethod + '\n' + canonicalURIParameter + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + signedHeader + '\n' + hashedPayload; } //Step 2: Create a string to sign using sig v4 public static String createStringToSign(String dateTime, String canonicalRequest, String accessKey, String date, String region) throws Exception { String credentialScope = date + "/" + region + "/" + serviceName + "/aws4_request"; return algorithm + '\n' + dateTime + '\n' + credentialScope + '\n' + BinaryUtils.toHex(hash(canonicalRequest)); } //Step 3: Calculate signature /** * Step 3 of the &AWS; Signature version 4 calculation. It involves deriving * the signing key and computing the signature. Refer to * http://docs.aws.amazon * .com/general/latest/gr/sigv4-calculate-signature.html */ public static byte[] calculateSignature(String stringToSign, byte[] signingKey) { return sign(stringToSign.getBytes(Charset.forName("UTF-8")), signingKey, SigningAlgorithm.HmacSHA256); } public static byte[] sign(byte[] data, byte[] key, SigningAlgorithm algorithm) throws SdkClientException { try { Mac mac = algorithm.getMac(); mac.init(new SecretKeySpec(key, algorithm.toString())); return mac.doFinal(data); } catch (Exception e) { throw new SdkClientException( "Unable to calculate a request signature: " + e.getMessage(), e); } } public static byte[] newSigningKey(String secretKey, String dateStamp, String regionName, String serviceName) { byte[] kSecret = ("AWS4" + secretKey).getBytes(Charset.forName("UTF-8")); byte[] kDate = sign(dateStamp, kSecret, SigningAlgorithm.HmacSHA256); byte[] kRegion = sign(regionName, kDate, SigningAlgorithm.HmacSHA256); byte[] kService = sign(serviceName, kRegion, SigningAlgorithm.HmacSHA256); return sign(AWS4_TERMINATOR, kService, SigningAlgorithm.HmacSHA256); } public static byte[] sign(String stringData, byte[] key, SigningAlgorithm algorithm) throws SdkClientException { try { byte[] data = stringData.getBytes(UTF8); return sign(data, key, algorithm); } catch (Exception e) { throw new SdkClientException( "Unable to calculate a request signature: " + e.getMessage(), e); } } //Step 4: append the signature public static String appendSignature(String signature) { return requestWithoutSignature + "&X-Amz-Signature=" + signature; } public static byte[] hash(String s) throws Exception { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(s.getBytes(UTF8)); return md.digest(); } catch (Exception e) { throw new SdkClientException( "Unable to compute hash while signing request: " + e.getMessage(), e); } } }

Connexion à votre instance de base de données

L'exemple de code suivant montre comment créer un jeton d'authentification, puis comment l'utiliser pour se connecter à une instance exécutant MariaDB ou MySQL.

Pour exécuter cet exemple de code, vous avez besoin de AWS SDK for Java, disponible sur le site AWS. En outre, vous avez besoin des éléments suivants :

  • MySQL Connector/J. Cet exemple de code a été testé avec mysql-connector-java-5.1.33-bin.jar.

  • Certificat intermédiaire pour Amazon RDS qui est spécifique à une région AWS. (Pour en savoir plus, consultez .) À l'exécution, le chargeur de classe recherche le certificat dans le même annuaire que celui de cet exemple de code Java, afin de pouvoir le trouver.

  • Modifiez la valeur des variables suivantes selon les besoins :

    • RDS_INSTANCE_HOSTNAME – Le nom d'hôte de l'instance de base de données auquel vous souhaitez accéder.

    • RDS_INSTANCE_PORT – Le numéro du port utilisé pour la connexion à votre instance de base de données PostgreSQL.

    • REGION_NAME – La région AWS où l'instance de base de données s'exécute.

    • DB_USER – Le compte de base de données auquel vous souhaitez accéder.

    • SSL_CERTIFICATE – Un sertificat SSL pour Amazon RDS qui est spécifique à une région AWS.

      Pour télécharger un certificat pour votre région AWS, veuillez consulter . Placez le certificat SSL dans le même annuaire que ce fichier de programme Java, afin que le chargeur de classe puisse le trouver à l'exécution.

Cet exemple de code obtient les informations d'identification AWS à partir de la chaîne de fournisseur d'informations d'identification par défaut.

Note

Spécifiez un mot de passe pour DEFAULT_KEY_STORE_PASSWORD différent de celui indiqué ici, en tant que bonne pratique de sécurité.

package com.amazonaws.samples; import com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator; import com.amazonaws.services.rds.auth.GetIamAuthTokenRequest; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.auth.AWSStaticCredentialsProvider; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; import java.net.URL; public class IAMDatabaseAuthenticationTester { //&AWS; Credentials of the IAM user with policy enabling IAM Database Authenticated access to the db by the db user. private static final DefaultAWSCredentialsProviderChain creds = new DefaultAWSCredentialsProviderChain(); private static final String AWS_ACCESS_KEY = creds.getCredentials().getAWSAccessKeyId(); private static final String AWS_SECRET_KEY = creds.getCredentials().getAWSSecretKey(); //Configuration parameters for the generation of the IAM Database Authentication token private static final String RDS_INSTANCE_HOSTNAME = "rdsmysql.123456789012.us-west-2.rds.amazonaws.com"; private static final int RDS_INSTANCE_PORT = 3306; private static final String REGION_NAME = "us-west-2"; private static final String DB_USER = "jane_doe"; private static final String JDBC_URL = "jdbc:mysql://" + RDS_INSTANCE_HOSTNAME + ":" + RDS_INSTANCE_PORT; private static final String SSL_CERTIFICATE = "rds-ca-2019-us-west-2.pem"; private static final String KEY_STORE_TYPE = "JKS"; private static final String KEY_STORE_PROVIDER = "SUN"; private static final String KEY_STORE_FILE_PREFIX = "sys-connect-via-ssl-test-cacerts"; private static final String KEY_STORE_FILE_SUFFIX = ".jks"; private static final String DEFAULT_KEY_STORE_PASSWORD = "changeit"; public static void main(String[] args) throws Exception { //get the connection Connection connection = getDBConnectionUsingIam(); //verify the connection is successful Statement stmt= connection.createStatement(); ResultSet rs=stmt.executeQuery("SELECT 'Success!' FROM DUAL;"); while (rs.next()) { String id = rs.getString(1); System.out.println(id); //Should print "Success!" } //close the connection stmt.close(); connection.close(); clearSslProperties(); } /** * This method returns a connection to the db instance authenticated using IAM Database Authentication * @return * @throws Exception */ private static Connection getDBConnectionUsingIam() throws Exception { setSslProperties(); return DriverManager.getConnection(JDBC_URL, setMySqlConnectionProperties()); } /** * This method sets the mysql connection properties which includes the IAM Database Authentication token * as the password. It also specifies that SSL verification is required. * @return */ private static Properties setMySqlConnectionProperties() { Properties mysqlConnectionProperties = new Properties(); mysqlConnectionProperties.setProperty("verifyServerCertificate","true"); mysqlConnectionProperties.setProperty("useSSL", "true"); mysqlConnectionProperties.setProperty("user",DB_USER); mysqlConnectionProperties.setProperty("password",generateAuthToken()); return mysqlConnectionProperties; } /** * This method generates the IAM Auth Token. * An example IAM Auth Token would look like follows: * btusi123.cmz7kenwo2ye.rds.cn-north-1.amazonaws.com.cn:3306/?Action=connect&DBUser=iamtestuser&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20171003T010726Z&X-Amz-SignedHeaders=host&X-Amz-Expires=899&X-Amz-Credential=AKIAPFXHGVDI5RNFO4AQ%2F20171003%2Fcn-north-1%2Frds-db%2Faws4_request&X-Amz-Signature=f9f45ef96c1f770cdad11a53e33ffa4c3730bc03fdee820cfdf1322eed15483b * @return */ private static String generateAuthToken() { BasicAWSCredentials awsCredentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY); RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder() .credentials(new AWSStaticCredentialsProvider(awsCredentials)).region(REGION_NAME).build(); return generator.getAuthToken(GetIamAuthTokenRequest.builder() .hostname(RDS_INSTANCE_HOSTNAME).port(RDS_INSTANCE_PORT).userName(DB_USER).build()); } /** * This method sets the SSL properties which specify the key store file, its type and password: * @throws Exception */ private static void setSslProperties() throws Exception { System.setProperty("javax.net.ssl.trustStore", createKeyStoreFile()); System.setProperty("javax.net.ssl.trustStoreType", KEY_STORE_TYPE); System.setProperty("javax.net.ssl.trustStorePassword", DEFAULT_KEY_STORE_PASSWORD); } /** * This method returns the path of the Key Store File needed for the SSL verification during the IAM Database Authentication to * the db instance. * @return * @throws Exception */ private static String createKeyStoreFile() throws Exception { return createKeyStoreFile(createCertificate()).getPath(); } /** * This method generates the SSL certificate * @return * @throws Exception */ private static X509Certificate createCertificate() throws Exception { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); URL url = new File(SSL_CERTIFICATE).toURI().toURL(); if (url == null) { throw new Exception(); } try (InputStream certInputStream = url.openStream()) { return (X509Certificate) certFactory.generateCertificate(certInputStream); } } /** * This method creates the Key Store File * @param rootX509Certificate - the SSL certificate to be stored in the KeyStore * @return * @throws Exception */ private static File createKeyStoreFile(X509Certificate rootX509Certificate) throws Exception { File keyStoreFile = File.createTempFile(KEY_STORE_FILE_PREFIX, KEY_STORE_FILE_SUFFIX); try (FileOutputStream fos = new FileOutputStream(keyStoreFile.getPath())) { KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE, KEY_STORE_PROVIDER); ks.load(null); ks.setCertificateEntry("rootCaCertificate", rootX509Certificate); ks.store(fos, DEFAULT_KEY_STORE_PASSWORD.toCharArray()); } return keyStoreFile; } /** * This method clears the SSL properties. * @throws Exception */ private static void clearSslProperties() throws Exception { System.clearProperty("javax.net.ssl.trustStore"); System.clearProperty("javax.net.ssl.trustStoreType"); System.clearProperty("javax.net.ssl.trustStorePassword"); } }

Si vous souhaitez vous connecter à une instance de bases de données via un proxy, consultez Connexion à un proxy à l'aide de l'authentification IAM.