SIGv4demandes authentifiées pour Amazon VPC Lattice - Amazon VPC Lattice

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.

SIGv4demandes authentifiées pour Amazon VPC Lattice

VPCLattice utilise Signature Version 4 (SIGv4) ou Signature Version 4A (SIGv4A) pour l'authentification du client. Pour plus d'informations, consultez la section Signature AWS API des demandes dans le guide de IAM l'utilisateur.

Considérations
  • VPCLattice tente d'authentifier toute demande signée avec SIGv4 ou. SIGv4A La demande échoue sans authentification.

  • VPCLattice ne prend pas en charge la signature de la charge utile. Vous devez envoyer un x-amz-content-sha256 en-tête dont la valeur est définie sur"UNSIGNED-PAYLOAD".

Python

Cet exemple envoie les demandes signées via une connexion sécurisée à un service enregistré sur le réseau. Si vous préférez utiliser des requêtes, le package botocore simplifie le processus d'authentification, mais n'est pas strictement obligatoire. Pour plus d'informations, consultez la section Credentials dans la documentation de Boto3.

Pour installer les awscrt packages botocore et, utilisez la commande suivante. Pour plus d'informations, consultez AWS CRTPython.

pip install botocore awscrt

Si vous exécutez l'application client sur Lambda, installez les modules requis à l'aide de couches Lambda ou incluez-les dans votre package de déploiement.

Dans l'exemple suivant, remplacez les valeurs de l'espace réservé par vos propres valeurs.

SIGv4
from botocore import crt import requests from botocore.awsrequest import AWSRequest import botocore.session if __name__ == '__main__': session = botocore.session.Session() signer = crt.auth.CrtSigV4Auth(session.get_credentials(), 'vpc-lattice-svcs', 'us-west-2') endpoint = 'https://data-svc-022f67d3a42.1234abc.vpc-lattice-svcs.us-west-2.on.aws' data = "some-data-here" headers = {'Content-Type': 'application/json', 'x-amz-content-sha256': 'UNSIGNED-PAYLOAD'} request = AWSRequest(method='POST', url=endpoint, data=data, headers=headers) request.context["payload_signing_enabled"] = False signer.add_auth(request) prepped = request.prepare() response = requests.post(prepped.url, headers=prepped.headers, data=data) print(response.text)
SIGv4A
from botocore import crt import requests from botocore.awsrequest import AWSRequest import botocore.session if __name__ == '__main__': session = botocore.session.Session() signer = crt.auth.CrtSigV4AsymAuth(session.get_credentials(), 'vpc-lattice-svcs', '*') endpoint = 'https://data-svc-022f67d3a42.1234abc.vpc-lattice-svcs.us-west-2.on.aws' data = "some-data-here" headers = {'Content-Type': 'application/json', 'x-amz-content-sha256': 'UNSIGNED-PAYLOAD'} request = AWSRequest(method='POST', url=endpoint, data=data, headers=headers) request.context["payload_signing_enabled"] = False signer.add_auth(request) prepped = request.prepare() response = requests.post(prepped.url, headers=prepped.headers, data=data) print(response.text)

Java avec intercepteur

Cet exemple utilise Amazon Request Signing Interceptor pour gérer la signature des demandes.

import com.amazonaws.http.AwsRequestSigningApacheInterceptor; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.auth.signer.Aws4UnsignedPayloadSigner; import software.amazon.awssdk.regions.Region; import java.nio.charset.StandardCharsets; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; public class App { public static void main(String[] args) { var interceptor = new AwsRequestSigningApacheInterceptor( "vpc-lattice-svcs", Aws4UnsignedPayloadSigner.create(), // requires HTTPS DefaultCredentialsProvider.create(), Region.US_WEST_2.id() ); CloseableHttpClient client = HttpClients.custom() .addInterceptorLast(interceptor) .build(); var httpPost = new HttpPost("https://user-02222f67d3a427111.1234abc.vpc-lattice-svcs.us-west-2.on.aws/create"); httpPost.addHeader("content-type", "application/json"); var body = """ { "name": "Jane Doe", "job": "Engineer" } """; httpPost.setEntity(new ByteArrayEntity(body.getBytes(StandardCharsets.UTF_8))); try (var response = client.execute(httpPost)) { System.out.println(new String(response.getEntity().getContent().readAllBytes())); } catch (Exception e) { throw new RuntimeException(e); } } }

Java sans intercepteur

Cet exemple montre comment vous pouvez effectuer la signature des demandes à l'aide d'intercepteurs personnalisés. Il utilise la classe de fournisseur d'informations d'identification par défaut from AWS SDK for Java 2.x, qui obtient les informations d'identification correctes pour vous. Si vous préférez utiliser un fournisseur d'informations d'identification spécifique, vous pouvez en sélectionner un parmi. AWS SDK for Java 2.x Le n' AWS SDK for Java autorise que les charges utiles non signées. HTTPS Cependant, vous pouvez étendre le signataire pour prendre en charge les charges utiles non signées. HTTP

import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.auth.signer.Aws4UnsignedPayloadSigner; import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.regions.Region; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; public class App { public static void main(String[] args) { var signer = Aws4UnsignedPayloadSigner.create(); // requires HTTPS Map<String, String> headers = new HashMap<>(); headers.put("content-type", "application/json"); var body = """ { "name": "Jane Doe", "job": "Engineer" } """; String endpoint = "https://user-02222f67d3a427111.1234abc.vpc-lattice-svcs.us-west-2.on.aws/create"; var sdkRequest = SdkHttpFullRequest.builder().method(SdkHttpMethod.POST); sdkRequest.host("user-02222f67d3a427111.1234abc.vpc-lattice-svcs.us-west-2.on.aws"); sdkRequest.protocol("HTTPS"); sdkRequest.encodedPath("/create"); sdkRequest.contentStreamProvider(() -> new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8))); for (Map.Entry<String, String> header : headers.entrySet()) { sdkRequest.putHeader(header.getKey(), header.getValue()); } ExecutionAttributes attributes = ExecutionAttributes.builder() .put(AwsSignerExecutionAttribute.AWS_CREDENTIALS, DefaultCredentialsProvider.create().resolveCredentials()) .put(AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME, "vpc-lattice-svcs") .put(AwsSignerExecutionAttribute.SIGNING_REGION, Region.US_WEST_2) .build(); SdkHttpFullRequest prepRequest = signer.sign(sdkRequest.build(), attributes); HttpPost httpPost = new HttpPost(endpoint); for (Map.Entry<String, List<String>> header : prepRequest.headers().entrySet()) { if (header.getKey().equalsIgnoreCase("host")) { continue; } for(var value : header.getValue()) { httpPost.addHeader(header.getKey(), value); } } CloseableHttpClient client = HttpClients.custom().build(); httpPost.setEntity(new ByteArrayEntity(body.getBytes(StandardCharsets.UTF_8))); try (var response = client.execute(httpPost)){ System.out.println(new String(response.getEntity().getContent().readAllBytes())); } catch (IOException e) { throw new RuntimeException(e); } } }

Node.js

Cet exemple utilise les liaisons NodeJS aws-crt pour envoyer une demande signée à l'aide de. HTTPS

Pour installer le aws-crt package, utilisez la commande suivante.

npm -i aws-crt

Si la variable d'AWS_REGIONenvironnement existe, l'exemple utilise la région spécifiée parAWS_REGION. La région par défaut estus-east-1.

SIGv4
const https = require('https') const crt = require('aws-crt') const { HttpRequest } = require('aws-crt/dist/native/http') function sigV4Sign(method, endpoint, service, algorithm) { const host = new URL(endpoint).host const request = new HttpRequest(method, endpoint) request.headers.add('host', host) // crt.io.enable_logging(crt.io.LogLevel.INFO) const config = { service: service, region: process.env.AWS_REGION ? process.env.AWS_REGION : 'us-east-1', algorithm: algorithm, signature_type: crt.auth.AwsSignatureType.HttpRequestViaHeaders, signed_body_header: crt.auth.AwsSignedBodyHeaderType.XAmzContentSha256, signed_body_value: crt.auth.AwsSignedBodyValue.UnsignedPayload, provider: crt.auth.AwsCredentialsProvider.newDefault() } return crt.auth.aws_sign_request(request, config) } if (process.argv.length === 2) { console.error(process.argv[1] + ' <url>') process.exit(1) } const algorithm = crt.auth.AwsSigningAlgorithm.SigV4; sigV4Sign('GET', process.argv[2], 'vpc-lattice-svcs').then( httpResponse => { var headers = {} for (const sigv4header of httpResponse.headers) { headers[sigv4header[0]] = sigv4header[1] } const options = { hostname: new URL(process.argv[2]).host, path: new URL(process.argv[2]).pathname, method: 'GET', headers: headers } req = https.request(options, res => { console.log('statusCode:', res.statusCode) console.log('headers:', res.headers) res.on('data', d => { process.stdout.write(d) }) }) req.on('error', err => { console.log('Error: ' + err) }) req.end() } )
SIGv4A
const https = require('https') const crt = require('aws-crt') const { HttpRequest } = require('aws-crt/dist/native/http') function sigV4Sign(method, endpoint, service, algorithm) { const host = new URL(endpoint).host const request = new HttpRequest(method, endpoint) request.headers.add('host', host) // crt.io.enable_logging(crt.io.LogLevel.INFO) const config = { service: service, region: process.env.AWS_REGION ? process.env.AWS_REGION : 'us-east-1', algorithm: algorithm, signature_type: crt.auth.AwsSignatureType.HttpRequestViaHeaders, signed_body_header: crt.auth.AwsSignedBodyHeaderType.XAmzContentSha256, signed_body_value: crt.auth.AwsSignedBodyValue.UnsignedPayload, provider: crt.auth.AwsCredentialsProvider.newDefault() } return crt.auth.aws_sign_request(request, config) } if (process.argv.length === 2) { console.error(process.argv[1] + ' <url>') process.exit(1) } const algorithm = crt.auth.AwsSigningAlgorithm.SigV4Asymmetric; sigV4Sign('GET', process.argv[2], 'vpc-lattice-svcs').then( httpResponse => { var headers = {} for (const sigv4header of httpResponse.headers) { headers[sigv4header[0]] = sigv4header[1] } const options = { hostname: new URL(process.argv[2]).host, path: new URL(process.argv[2]).pathname, method: 'GET', headers: headers } req = https.request(options, res => { console.log('statusCode:', res.statusCode) console.log('headers:', res.headers) res.on('data', d => { process.stdout.write(d) }) }) req.on('error', err => { console.log('Error: ' + err) }) req.end() } )

Golang - GRPC

Cet exemple utilise le langage de programmation AWS SDK for the Go pour gérer la signature des GRPC demandes. Cela peut être utilisé avec le serveur Echo à partir du référentiel GRPC d'exemples de code.

package main import ( "context" "crypto/tls" "crypto/x509" "flag" "fmt" "log" "net/http" "net/url" "strings" "time" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "github.com/aws/aws-sdk-go-v2/aws" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/config" ecpb "google.golang.org/grpc/examples/features/proto/echo" ) const ( headerContentSha = "x-amz-content-sha256" headerSecurityToken = "x-amz-security-token" headerDate = "x-amz-date" headerAuthorization = "authorization" unsignedPayload = "UNSIGNED-PAYLOAD" ) type SigV4GrpcSigner struct { service string region string credProvider aws.CredentialsProvider signer *v4.Signer } func NewSigV4GrpcSigner(service string, region string, credProvider aws.CredentialsProvider) *SigV4GrpcSigner { signer := v4.NewSigner() return &SigV4GrpcSigner{ service: service, region: region, credProvider: credProvider, signer: signer, } } func (s *SigV4GrpcSigner) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { ri, _ := credentials.RequestInfoFromContext(ctx) creds, err := s.credProvider.Retrieve(ctx) if err != nil { return nil, fmt.Errorf("failed to load credentials: %w", err) } // The URI we get here is scheme://authority/service/ - for siging we want to include the RPC name // But RequestInfoFromContext only has the combined /service/rpc-name - so read the URI, and // replace the Path with what we get from RequestInfo. parsed, err := url.Parse(uri[0]) if err != nil { return nil, err } parsed.Path = ri.Method // Build a request for the signer. bodyReader := strings.NewReader("") req, err := http.NewRequest("POST", uri[0], bodyReader) if err != nil { return nil, err } date := time.Now() req.Header.Set(headerContentSha, unsignedPayload) req.Header.Set(headerDate, date.String()) if creds.SessionToken != "" { req.Header.Set(headerSecurityToken, creds.SessionToken) } // The signer wants this as //authority/path // So get this by triming off the scheme and the colon before the first slash. req.URL.Opaque = strings.TrimPrefix(parsed.String(), parsed.Scheme+":") err = s.signer.SignHTTP(context.Background(), creds, req, unsignedPayload, s.service, s.region, date) if err != nil { return nil, fmt.Errorf("failed to sign request: %w", err) } // Pull the relevant headers out of the signer, and return them to get // included in the request we make. reqHeaders := map[string]string{ headerContentSha: req.Header.Get(headerContentSha), headerDate: req.Header.Get(headerDate), headerAuthorization: req.Header.Get(headerAuthorization), } if req.Header.Get(headerSecurityToken) != "" { reqHeaders[headerSecurityToken] = req.Header.Get(headerSecurityToken) } return reqHeaders, nil } func (c *SigV4GrpcSigner) RequireTransportSecurity() bool { return true } var addr = flag.String("addr", "some-lattice-service:443", "the address to connect to") var region = flag.String("region", "us-west-2", "region") func callUnaryEcho(client ecpb.EchoClient, message string) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() resp, err := client.UnaryEcho(ctx, &ecpb.EchoRequest{Message: message}) if err != nil { log.Fatalf("client.UnaryEcho(_) = _, %v: ", err) } fmt.Println("UnaryEcho: ", resp.Message) } func main() { flag.Parse() cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithClientLogMode(aws.LogSigning)) if err != nil { log.Fatalf("failed to load SDK configuration, %v", err) } pool, _ := x509.SystemCertPool() tlsConfig := &tls.Config{ RootCAs: pool, } authority, _, _ := strings.Cut(*addr, ":") // Remove the port from the addr opts := []grpc.DialOption{ grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), // Lattice needs both the Authority to be set (without a port), and the SigV4 signer grpc.WithAuthority(authority), grpc.WithPerRPCCredentials(NewSigV4GrpcSigner("vpc-lattice-svcs", *region, cfg.Credentials)), } conn, err := grpc.Dial(*addr, opts...) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() rgc := ecpb.NewEchoClient(conn) callUnaryEcho(rgc, "hello world") }