# Introdução

Um guia prático para a caminhada devops em ambiente cloud

Este projeto tem por objetivo , com demonstração prática, compartilhar o fluxo de criação de conta na AWS bem como a utilização do AWS CLI pela linha de comando no terminal, com o intuito de provisionar uma instância virtual no EC2 e acessá-la através de SSH.

Resumo do código para os mais ansiosos :point\_down: *Para os pacientes, pode seguir para a próxima página.*

```bash
aws configure --profile personal

aws --profile personal ec2 \
    create-key-pair \
    --key-name aws-ssh-key \
    --key-type ed25519 | \
    jq -r '.KeyMaterial' > ~/.ssh/aws-ssh-key.pem

aws --profile personal ec2 \
    create-security-group \
    --group-name instances-sg \
    --description "Security Group for EC2 instances" \
    --tag-specifications "ResourceType=security-group,Tags=[{Key=Name,Value=instances-sg}]" | \
    jq -r '.GroupId'

aws --profile personal ec2 \
    authorize-security-group-ingress \
    --group-id <sg-group-id> \
    --protocol tcp --port 22 --cidr 0.0.0.0/0

aws --profile personal ec2 \
    run-instances --image-id ami-0c4f7023847b90238 \
    --instance-type t2.micro \
    --key-name aws-ssh-key \
    --security-group-ids <sg-group-id> \
    --associate-public-ip-address \
    --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=myapp}]" \
    --count 1 | \
    jq -r '.Instances[0].InstanceId'

chmod 400 ~/.ssh/aws-ssh-key.pem

ssh ubuntu@<public-ip> -i ~/.ssh/aws-ssh-key.pem
```


# Criar uma conta na AWS

Para o desenvolvimento do projeto, vamos utilizar o ambiente da AWS para configuração dos servidores e serviços.&#x20;

### Registro e informações pessoais

Começamos por [criar uma conta](https://portal.aws.amazon.com/billing/signup#/start/email) e seguir os passos para preencher informações pessoais.

### Forma de pagamento

Deve-se escolher uma forma de pagamento para cobrança da utilização dos serviços, entretanto a AWS disponibiliza um período "trial" chamado **Free Tier** onde, durante 12 meses, alguns serviços específicos não são cobrados. [Consulte aqui](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html) mais informações sobre o free tier.

### Adicionando segurança à conta

Uma vez criada a conta raiz, o acesso é feito através do email escolhido. A conta raiz tem acesso *ilimitado* aos serviços da AWS e portanto deve ser protegida com máximo cuidado.&#x20;

1. Escolher uma senha forte: a escolha da senha é muito importante. É recomendado o uso de [password managers](https://en.wikipedia.org/wiki/Password_manager) como [bitwarden](https://bitwarden.com/), [1Password](https://1password.com/) entre outros. E não apenas para AWS, mas para armazenamento seguro de tuas passwords pessoais em qualquer serviço na internet.
2. No menu "Security Credentials", há uma opção para habilitar uso de [MFA](https://en.wikipedia.org/wiki/Multi-factor_authentication). Não conte com a sorte e habilite-o, principalmente em uma conta que tem acesso ilimitado aos recursos que serão cobrados no *teu* cartão de crédito.

### Criando um user "devops" no IAM

Nosso intuito é que, através da linha de comando, possamos utilizar um [CLI](https://aws.amazon.com/cli/) que crie, atualize e apague recursos na nossa conta da AWS.&#x20;

Para tanto, é necessário que o user associado à conta tenha acesso "programático" (*programmatic access),* através de uma chave segura de acesso e uma senha para esta chave.&#x20;

Podemos configurar a chave e senha ainda no menu "Security Credentials" do root user, mas não queremos que este user da conta tenha este tipo de acesso, pois caso as credenciais sejam roubadas, a conta fica comprometida pois este user tem acesso ilimitado.&#x20;

Para resolver isto, é recomendado que criemos **outro user** com permissões limitadas a um conjunto de serviços na AWS. A AWS disponibiliza de um serviço chamado [IAM](https://us-east-1.console.aws.amazon.com/iamv2/home#/home) que permite criar diversos users e definir permissões específicas para cada user.

Primeiro, vamos adicionar um user que terá acesso programático:

![](/files/6GVz88TpdauODYT7V4Ek)

Agora, devemos configurar as permissões específicas para este user. No nosso caso, precisa apenas de acesso full ao [EC2](https://aws.amazon.com/pt/ec2/):

![](/files/rfa4gSpgUlqLc1BxxNnK)

Um arquivo `.csv` vai ser gerado. Devemos guardar o arquivo em segurança, pelo que dentro dele temos a password inicial para acesso web a este user bem como as credenciais do CLI.

Após o user ser criado, e ainda na console web da AWS, devemos fazer o logout do root por segurança, e realizar o primeiro login com o novo user, utilizando a password gerada no arquivo CSV.

### Adicionando segurança à conta do IAM user

Assim como fizemos na conta raiz, é importante também escolher uma senha forte para o IAM user bem como habilitar MFA (multi-factor).

#### E pronto,

temos uma conta AWS devidamente criada, segura e com acesso limitado por meio de user criado no IAM.


# Configurar AWS CLI

Após termos uma conta devidamente criada, a seguir é necessário que façamos a instalação e configuração do executável [AWS CLI](https://aws.amazon.com/cli/) na linha de comando do terminal.&#x20;

### Instalação

Siga [este passos](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) para instalação de acordo com teu sistema operacional.

### Configuração

Vamos começar por executar `aws configure --profile personal`. O CLI irá pedir a chave de acesso e a senha, que estão no `.csv` gerado no momento da criação do IAM user.

Irá pedir também a `region` e `output`, que podem ser `us-east-1` (North Virginia) e `json`, respectivamente.&#x20;

No fim, o CLI deverá ter criado os arquivos `~./.aws/credentials` e `~/.aws/config`. Pode conferir com o comando `cat`:

```bash
leandronsp:~ $ cat ~/.aws/credentials 
[personal]
aws_access_key_id = AKIA******Y9
aws_secret_access_key = aBTL***************DroW
```

```bash
leandronsp:~ $ cat ~/.aws/config
[profile personal]
region = us-east-1
output = json
```

### Utilizando a API do AWS CLI

A [API do AWS CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/index.html) é vasta, cobrindo quase todos senão todos os serviços existentes na AWS. Praticamente tudo o que conseguimos fazer pela console web, deveríamos também conseguir pelo AWS CLI.&#x20;

Isto abre portas para todo um mundo de automação, e sendo esta capacidade não exclusiva apenas à AWS, outros cloud-providers como GCP e Microsoft Azure  possuem também seus respectivos CLI's com acesso a todos os serviços existentes.&#x20;

Se você digitar `aws` no terminal, verá que ele mostra a utilização do comando, que tem o seguinte padrão:

```bash
aws <command> <subcommand>
```

Onde "command" representa um serviço específico da AWS (como `ec2`, `s3`, etc) e "subcommand" é uma das ações disponíveis para aquele serviço em específico.

#### Listar as instâncias virtuais no EC2

```bash
aws --profile personal ec2 describe-instances

### note que o "profile", quando passado como opção, 
### vai utilizar as credenciais [personal] do arquivo 
### ~/.aws/credentials. 
#
### caso queira omitir, tem que executar o `aws configure` sem o profile,
### para que seja utilizado como profile default.
```

Output:

```bash
{
    "Reservations": []
}
```

No nosso caso, ainda não temos nenhuma instância virtual criada, pelo que será o objetivo das próximas sessões.&#x20;


# Instalar jq - JSON processor

Como podemos reparar, o output escolhido por nós no `aws configure` é o `json`. Assim, para que tiremos máximo proveito da automação, é interessante que consigamos processar o output.&#x20;

Para isto, podemos utilizar a [biblioteca jq](https://stedolan.github.io/jq/), que ajuda muito no processo de automação.&#x20;

Uma vez instalado, podemos processar o output a extrair informações relevantes, como o exemplo abaixo que extrai o ID da instância:

```bash
leandronsp:~ $ 
    aws --profile personal ec2 describe-instances | \
        jq -r '.Reservations[0].Instances[0].InstanceId'

#=> i-0efdd68b789a70981
```


# Criar key-pair no EC2

Antes de criarmos a instância, é *extremamente* necessário deixá-la segura. Uma das medidas de segurança passa por criarmos um **par de chaves** onde, ao entrarmos na instância via SSH (porta 22), enviamos uma parte da chave que será utilizada para verificar sua autenticidade *com a outra parte, guardada previamente* no servidor. Desta forma, qualquer acesso SSH sem a chave será negado.&#x20;

A este par de chaves damos o nome de [criptografia assimétrica](https://en.wikipedia.org/wiki/Public-key_cryptography), onde a chave guardada no computador do user é a **privada** e a outra parte guardada no servidor é a **pública**.

Para nossa sorte, a AWS permite criar um par de chaves via CLI. A chave pública fica guardada na nossa conta da AWS e pode ser utilizada nas instâncias que iremos criar. E no output do comando, vamos extrair o conteúdo da chave privada para guardarmos no nosso computador e utilizá-la quando quisermos acessar as instâncias que iremos criar.

```bash
aws --profile personal ec2 \
    create-key-pair \
    --key-name aws-ec2-key \
    --key-type ed25519 \
    | jq -r '.KeyMaterial' > ~/.ssh/aws-ec2-key.pem
```

* `ec2` é o nome do serviço na AWS
* `create-key-pair` é o nome da ação&#x20;
* na opção `key-name` especificamos o nome da nossa chave na AWS
* com `key-type` escolhemos o [algoritmo de criptografia](https://en.wikipedia.org/wiki/EdDSA)
* depois, com [pipe](https://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-4.html) (`|`), mandamos o output para ser extraído conteúdo da chave privada com `jq`
* no fim, jogamos (`>`) o output final com a chave privada em um arquivo chamado `~/.ssh/aws-ec2-key.pem`, que será utilizado posteriormente quando entrarmos nas instâncias com SSH

#### Verificando que a chave foi criada

```bash
leandronsp:~ $ aws --profile personal ec2 \
    describe-key-pairs \
    | jq -r '.KeyPairs[0].KeyName'
    
aws-ec2-key
```


# Criar regra de firewall no EC2

Por padrão, quando uma instância é criada no EC2, lhe é atribuída uma regra de firewall, que no EC2 se chamam **Security Groups**.&#x20;

A regra *default* é que a instância fica com todas as portas abertas para toda a internet. Em termos de segurança, não queremos deixar nosso servidor tão exposto assim.&#x20;

Portanto, o único acesso inicial que queremos dar à nossa instância *é na porta 22 para que possamos fazer SSH* e entrar na máquina.&#x20;

Com isto em mente, queremos criar nossa instância com um security group customizado por nós onde o único acesso é através da porta 22, deixando todas as outras fechadas por default.&#x20;

#### Criando um security group via CLI

Podemos criar quantos security groups (sg) quisermos no EC2, inclusive adicionar e remover regras de firewall a estes security groups.&#x20;

```bash
aws --profile personal ec2 \
    create-security-group \
    --group-name instances-sg \
    --description "Security Group for EC2 instances" \
    --tag-specifications "ResourceType=security-group,Tags=[{Key=Name,Value=instances-sg}]"
```

A opção `tag-specifications` é opcional e muito útil para definirmos labels e nomes para nossos recursos na AWS, para uma melhor visualização e filtragem na interface web.

No output, deverá ter toda a informação do security group, incluindo o `SecurityGroupId`.

#### Adicionando regras de ingress no security group

Nosso security group está criado mas não possui nenhuma regra. Ele é completamente *fechado por default*. Precisamos abrir o necessário, no nosso caso, a porta 22, utilizando a ação `authorize-security-group-ingress`:

```bash
aws --profile personal ec2 \
    authorize-security-group-ingress \
    --group-id <g-group-id> \ <---------- mudar para o ID do security group
    --protocol tcp --port 22 --cidr 0.0.0.0/0
```

A opção `--protocol` define o tipo de protocolo, no caso TCP; a porta 22; e o bloco [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) que, no nosso exemplo, permite qualquer interface de rede da internet, `0.0.0.0/0.`

#### E pronto,&#x20;

temos um security group devidamente criado a configurado, pronto para ser utilizado na nossa futura instância virtual.


# Criar instância virtual no EC2

Uma vez que temos o key-pair e security group definidos, podemos criar nossa instância virtual:

```bash
aws --profile personal ec2 \
    run-instances \
    --image-id ami-0c4f7023847b90238 \
    --instance-type t2.micro \
    --key-name aws-ec2-key \
    --security-group-ids <sg-group-id> \
    --associate-public-ip-address \
    --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=myapp}]" \
    --count 1
```

Explicação do comando a seguir:

#### run-instances

A ação se chama `run-instances`, que cria uma ou mais instâncias virtuais a partir de uma imagem de sistema operacional pré-definida no AWS.

#### image-id

Identificador da imagem (AMI) na AWS. Exemplo da lista de AMI's quando se cria instância pela interface web:

![](/files/twAp63KmiuD9UdB1ASar)

No nosso caso, utilizamos a AMI `ami-0c4f7023847b90238` que é referente ao Ubuntu Server 20.04 LTS.&#x20;

#### instance-type

Tipo da instância, neste caso sendo `t2.micro` que tem 1GB de memória e faz parte do período *free tier.*

#### key-name

Nome da chave `key-pair` criada previamente, que se chama `aws-ec2-key`. A AWS vai atribuir a chave pública do par nesta instância, assim poderemos posteriormente fazer SSH com a parte privada que já guardamos nos steps anteriores.

#### security-group-ids

Lista de ID's de security groups. Neste exemplo usamos aquele criado previamente, que por regra abre somente a porta 22 (SSH).

#### outras opções

* `--associate-public-ip-address`: associa um IP público à instância. Sem esta opção, a instância não irá ter IP público, apenas privado dentro da mesma rede interna da conta (VPC).
* `--count`: número de instâncias a serem criadas com estas especificações, no nosso caso apenas 1.
* `--tag-specifications`: dar uma tag "Name" à instância, para melhor visualização na interface web.

### Verificando que a instância foi criada

Nossa instância foi criada. Para verificar que foi criada, bem como sabe qual o IP público pra acesso SSH:

```bash
aws --profile personal ec2 \
    describe-instances \
    --filters "Name=tag:Name,Values=myapp" | \
    jq -r '.Reservations[0].Instances[0].PublicIpAddress'
```

#### Testando acesso SSH à instância virtual

Sabendo o IP público, que dá pra extrair tanto pelo CLI como vimos no último passo como também através da interface web, podemos fazer o SSH utilizando a chave privada.&#x20;

Mas antes, vamos marcar a chave como sendo apenas de leitura:

```bash
# definindo apenas permissão de leitura à chave, pois por segurança,
# o server rejeita uma chave pública que tenha permissões de escritas,
# evitando assim ataques de key-pair que possam forjar uma chave igual

chmod 400 ~/.ssh/aws-ssh-key.pem
```

Agora podemos, seguramente, fazer nosso primeiro acesso SSH ao server:

```bash
ssh ubuntu@<public-ip> -i ~/.ssh/aws-ssh-key.pem
```

![um print pra ser lembrado](/files/QCvmg83pzrEOMgAwZzOq)


