Utilizando AWS Secret Manager com K6🔐
Tags: testing, k6, performance
Published: 2023-06-13 23:10:33

Ao escrever scripts de teste, é crucial que mantenhamos um alto nível de preocupação com a exposição de dados sensíveis, assim como teríamos ao desenvolver um software. 

Isso se deve ao fato de que um vazamento de credenciais ou informações confidenciais da aplicação testada pode ter consequências graves, comprometendo a segurança e até mesmo resultando em incidentes de segurança. Portanto, é imprescindível tomar medidas adequadas para garantir a proteção desses dados durante todo o processo de teste.

Em um post anterior, discutimos como podemos [utilizar variáveis de ambiente com K6](utilizar variáveis de ambiente com K6). Essa abordagem nos permite passar valores para o script por meio de definições na linha de comando (CLI).

Neste artigo, exploraremos o uso do AWS Secret Manager para o gerenciamento e recuperação de credenciais e segredos.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1hvdxltquvaugqrihnp.png)

## O que é o AWS Secret Manager🔐

O AWS Secret Manager é um serviço  que permite armazenar e gerenciar de forma segura as informações sensíveis, como credenciais de acesso, chaves de API, senhas e outros segredos.

Pense no AWS Secret Manager como uma espécie de cofre virtual. Em vez de armazenar senhas e informações confidenciais em arquivos, o Secret Manager oferece um local seguro e centralizado para guardar esses segredos.

O Secret Manager também permite gerenciar o acesso aos segredos, concedendo permissões granulares aos usuários ou serviços que precisam utilizá-los. Isso garante que apenas as pessoas autorizadas possam acessar essas informações.

Além disso, o Secret Manager facilita a rotação de segredos, ou seja, a atualização periódica de senhas e chaves. Com isso, é possível garantir a segurança contínua dos sistemas, mesmo se algum segredo for comprometido.

## Pré-requisitos📑
- [K6 instalado](https://k6.io/docs/get-started/installation/)
- Conta na AWS

## Criando nosso segredo🔧
Ao acessar o [console da AWS](https://us-east-1.console.aws.amazon.com/console/home?region=us-east-1), pesquise pelo serviço [Secret Manager](https://us-east-1.console.aws.amazon.com/secretsmanager/landing?region=us-east-1):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bascaln1vxw69t8id21y.png)

Para começar a configurar seu segredo no Secret Manager, escolha a opção _Armazenar um novo segredo_.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8r89ldzbvy4119mtlun.png)

O processo de criação de um segredo no Secret Manager consiste em quatro fases: seleção do tipo de segredo, configuração do segredo, configuração de alternância do segredo e análise do segredo.

### Seleção do tipo de segredo🎲
A primeira informação que precisamos fornecer é o tipo do segredo. Neste caso, estaremos armazenando uma credencial de acesso, portanto, selecionaremos a opção _Outro tipo de segredo_:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt0sa0zvs7mnpjrl37lu.png)

Quando selecionamos a opção _Outro tipo de segredo_, os segredos são definidos como pares de chave e valor. Neste exemplo, vamos preencher o campo chave com _token_acesso_ e o campo valor com um token JWT de sessão de um usuário na API [auth/token/login](https://test-api.k6.io/auth/token/login/) do K6.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6mulzylm2gn7fp7szlti.png)

No campo de chave de criptografia, permitiremos que o Secret Manager utilize uma chave criada por ele, utilizando [KMS](https://aws.amazon.com/pt/kms/).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eqzkqkq9l7xc59ghi7e8.png)

Após fornecer essas informações podemos clicar em próximo.

### Configuração do segredo🔗

Na opção de configuração do segredo, é necessário fornecer o nome do segredo e uma descrição. Além disso, existem outras informações opcionais que podem ser fornecidas, como tags, permissões de recursos e a opção de replicar o segredo.

No campo nome do segredo daremos o nome de curso_k6. E na descrição informaremos que esse é um segredo de credencial de acesso a API.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uynkmbakx7gmovdo7vy4.png)

> É importante ressaltar que, embora sejam opcionais, as "Permissões de Recursos" são extremamente importantes quando precisamos definir [políticas de acesso a recursos da AWS](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html).

### Configuração de alternância do segredo👥

Na opção de configuração de alternância vamos deixar todas as opções defaults sem realizar modificações.

> É essencial ressaltar que, com essa configuração, teríamos a capacidade de atualizar automaticamente as informações do nosso segredo em intervalos de tempo pré-determinados.  

### Análise do segredo🔍

Na opção de análise, oferecemos a oportunidade de revisar as informações do segredo a ser criado no Secret Manager, juntamente com algumas implementações de acesso em várias linguagens.

Ao selecionar _Armazenar_, você será redirecionado para a tela de listagem de segredos, onde poderá verificar que o nosso segredo foi criado com êxito.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swwbdi6wdymf4arzn7u1.png)

## Mão na massa👩‍💻

Nesta etapa prática, faremos modificações em um script de teste de performance que requer um token de usuário. Utilizaremos o Secret Manager para recuperar esse token do nosso segredo.

O exemplo de script que será utilizado é o seguinte:

```
import http from 'k6/http';
import { check, sleep } from 'k6';

const BASE_URL = 'https://test-api.k6.io';

export default function(){
    
    const params = {
        headers: {
            Authorization: `Bearer ${token}` ,
            'Content-Type': 'application/json'
        }
    }
    const res = http.get(`${BASE_URL}/my/crocodiles`, params);

    check(res, {
        'status code 200': (r) => r.status === 200
    });
}
```

### Utilizando o nosso segredo😃

Para começar, vamos importar os módulos que concedem acesso aos recursos da AWS. O K6 oferece um módulo na biblioteca [K6 js lib](https://github.com/grafana/k6-jslib-aws). Adicione o seguinte módulo à fase de inicialização:

```
import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.4.0/secrets-manager.js'
```

Precisamos configurar o acesso remoto a AWS, e para isso precisamos das seguintes informações: region, accessKeyId e secretAccessKey. 

A região é o local onde seus recursos da AWS foram criados. Nosso segredo foi criado na região us-east-1. Quanto ao _accessKeyId_ e _secretAccessKey_, são informações altamente confidenciais necessárias para o acesso remoto. 

Instruções sobre como gerar o accessKeyId e secretAccessKey podem ser encontradas no seguinte link: [intruções](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)

Defina na fase de configuração uma variável que implemente o AWSConfig, como mostrado abaixo:

```
const awsConfig = new AWSConfig({
    region: 'us-east-1',
    accessKeyId: __ENV.AWS_ACCESS_KEY_ID,
    secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY,
});
```

> Vamos definir duas variáveis de ambiente com os nomes AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY. Para obter instruções sobre como definir variáveis de ambiente com K6, recomendo a leitura do artigo: [Utilizando variáveis de ambiente com K6](https://dev.to/marlo2222/utilizando-variaveis-de-ambiente-com-k6-28k7).

Com o objeto AWSConfig criado, vamos adicionar outra variável na fase de inicialização para implementar o objeto SecretsManagerClient. Adicione a seguinte linha ao seu código:

```
const secretsManager = new SecretsManagerClient(awsConfig);
```
 
Para buscar o nosso segredo, vamos definir uma função na fase de configuração com o nome _setup_. Essa função realizará um único acesso ao Secret Manager para obter a credencial necessária, em seguida, passará essa credencial para a função padrão na fase de execução.
 
```
export function setup(){
    const segredo = secretsManager.getSecret('curso_k6');
    return JSON.parse(segredo.secret);
}
```

> Observe que estamos utilizando uma das funções disponíveis no objeto secretsManager que criamos, mais especificamente a função getSecret, que nos permite buscar os valores de um segredo. No nosso exemplo, o segredo que estamos buscando é chamado _curso_k6_. 

Por fim, na fase de execução precisamos apenas adicionar o parâmetro que será passado para a função default, no caso token:

```
export default function(token)
```
Nosso script após ajustes ficara da seguinte forma:

```
import http from 'k6/http';
import { check } from 'k6';
import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.7.2/secrets-manager.js';

const awsConfig = new AWSConfig({
    region: "us-east-1",
    accessKeyId: __ENV.AWS_ACCESS_KEY_ID,
    secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY,
});

const secretsManager = new SecretsManagerClient(awsConfig);

export function setup(){
    const segredo = secretsManager.getSecret('curso_k6');
    return JSON.parse(segredo.secret);
}

const BASE_URL = 'https://test-api.k6.io';

export default function(token){

    const params = {
        headers: {
            Authorization: `Bearer ${token.token_acesso}` ,
            'Content-Type': 'application/json'
        }
    }
    const res = http.get(`${BASE_URL}/my/crocodiles`, params);

    check(res, {
        'status code 200': (r) => r.status === 200
    });
}
```

> Ponto importante a ser observado: o nosso token é na verdade, um objeto JSON. Portanto, precisamos acessar a chave desse objeto, que no caso é _token_acesso_. É importante ressaltar que um mesmo segredo pode ter vários pares chave-valor associados a ele.

Por fim, para executarmos o nosso script podemos utilizar o seguinte comando:

```
 k6 run -e AWS_ACCESS_KEY_ID='',AWS_SECRET_ACCESS_KEY='' secret_manager.js        
```

> Substitua as aspas simples por seu AWS_ACESS_KEY_ID e AWS_SECRET_ACESS_KEY

Podemos observar que o token do usuário foi buscado corretamente no Secret Manager:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4gdsdaueg97s8pjm4jem.png)

### Executando via AWS☁️

Caso você deseje executar o script via AWS, ele ficará ainda mais simplificado. As informações AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY são necessárias apenas localmente, dentro do ambiente da AWS você já terá acesso ao Secret Manager, desde que as políticas de acesso estejam configuradas corretamente para o seu usuário.

Nosso script ficaria da seguinte forma para execução via AWS:
```
import http from 'k6/http';
import { check } from 'k6';
import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.7.2/secrets-manager.js';

const awsConfig = new AWSConfig({
    region: "us-east-1",
});

const secretsManager = new SecretsManagerClient(awsConfig);

export function setup(){
    const segredo = secretsManager.getSecret('curso_k6');
    return JSON.parse(segredo.secret);
}

const BASE_URL = 'https://test-api.k6.io';

export default function(token){

    const params = {
        headers: {
            Authorization: `Bearer ${token.token_acesso}` ,
            'Content-Type': 'application/json'
        }
    }
    const res = http.get(`${BASE_URL}/my/crocodiles`, params);

    check(res, {
        'status code 200': (r) => r.status === 200
    });
}
```
### Conclusão💖
Podemos observar que com poucas modificações, foi possível utilizar uma ferramenta altamente confiável de gerenciamento de segredos, evitando que informações sensíveis fossem incorporadas diretamente nos nossos scripts. 🤗

O módulo _SecretsManagerClient_ oferece uma ampla variedade de recursos, como criação de segredos, listagem, remoção, recuperação, alteração de valores e muito mais. Possivelmente, este artigo se transformará em uma série que abordará outros módulos da lib AWS.😀

Gostou do conteúdo e quer saber mais sobre testes de performance com K6? Então não deixe de conferir meu curso na Udemy: 

- [Teste de performance com K6](https://www.udemy.com/course/teste-de-performance-com-k6/?referralCode=95CCD8BC9F22A2A96BDA)