128 lines
8.3 KiB
Bash
128 lines
8.3 KiB
Bash
(set -o noclobber; aw ec2 create-key-pair --key-name "$KEY_NAME" \
|
|
--tag-specifications "$(tags key-pair ssh)" --query KeyMaterial --output text > "$key_file")
|
|
chmod 600 "$key_file"
|
|
[[ -s "$key_file" ]] || { echo 'Arquivo da chave vazio.' >&2; return 1; }
|
|
record PrivateKeyFile "$key_file"
|
|
fi
|
|
local vpc igw public_subnet private_subnet public_rt private_rt gateway_sg services_sg gateway server
|
|
vpc=$(aw ec2 create-vpc --cidr-block 10.20.0.0/16 --tag-specifications "$(tags vpc vpc)" --query Vpc.VpcId --output text)
|
|
record VpcId "$vpc"
|
|
aw ec2 wait vpc-available --vpc-ids "$vpc"
|
|
aw ec2 modify-vpc-attribute --vpc-id "$vpc" --enable-dns-support '{"Value":true}'
|
|
aw ec2 modify-vpc-attribute --vpc-id "$vpc" --enable-dns-hostnames '{"Value":true}'
|
|
igw=$(aw ec2 create-internet-gateway --tag-specifications "$(tags internet-gateway igw)" --query InternetGateway.InternetGatewayId --output text)
|
|
record InternetGatewayId "$igw"
|
|
aw ec2 attach-internet-gateway --internet-gateway-id "$igw" --vpc-id "$vpc"
|
|
public_subnet=$(aw ec2 create-subnet --vpc-id "$vpc" --cidr-block 10.20.1.0/24 --availability-zone "$az" --tag-specifications "$(tags subnet publica)" --query Subnet.SubnetId --output text)
|
|
record PublicSubnetId "$public_subnet"
|
|
private_subnet=$(aw ec2 create-subnet --vpc-id "$vpc" --cidr-block 10.20.2.0/24 --availability-zone "$az" --tag-specifications "$(tags subnet privada)" --query Subnet.SubnetId --output text)
|
|
record PrivateSubnetId "$private_subnet"
|
|
public_rt=$(aw ec2 create-route-table --vpc-id "$vpc" --tag-specifications "$(tags route-table publica)" --query RouteTable.RouteTableId --output text)
|
|
record PublicRouteTableId "$public_rt"
|
|
aw ec2 associate-route-table --route-table-id "$public_rt" --subnet-id "$public_subnet" >/dev/null
|
|
aw ec2 create-route --route-table-id "$public_rt" --destination-cidr-block 0.0.0.0/0 --gateway-id "$igw" >/dev/null
|
|
private_rt=$(aw ec2 create-route-table --vpc-id "$vpc" --tag-specifications "$(tags route-table privada)" --query RouteTable.RouteTableId --output text)
|
|
record PrivateRouteTableId "$private_rt"
|
|
aw ec2 associate-route-table --route-table-id "$private_rt" --subnet-id "$private_subnet" >/dev/null
|
|
gateway_sg=$(aw ec2 create-security-group --vpc-id "$vpc" --group-name "$LAB_NAME-gateway" --description 'Gateway OpenVPN do laboratorio' --tag-specifications "$(tags security-group gateway)" --query GroupId --output text)
|
|
record GatewaySecurityGroupId "$gateway_sg"
|
|
services_sg=$(aw ec2 create-security-group --vpc-id "$vpc" --group-name "$LAB_NAME-servicos" --description 'Servicos privados do laboratorio' --tag-specifications "$(tags security-group servicos)" --query GroupId --output text)
|
|
record ServicesSecurityGroupId "$services_sg"
|
|
allow() { aw ec2 authorize-security-group-ingress --group-id "$1" --protocol "$2" --port "$3" --cidr "$4" >/dev/null; }
|
|
allow "$gateway_sg" tcp 22 0.0.0.0/0
|
|
allow "$gateway_sg" udp 1194 0.0.0.0/0
|
|
# Comunicacao interna irrestrita na VPC; saida padrao dos grupos ja permite tudo.
|
|
local internal_sg internal_cidr
|
|
for internal_sg in "$gateway_sg" "$services_sg"; do
|
|
for internal_cidr in 10.20.0.0/16 "$LOCAL_CIDR" "$VPN_CIDR"; do
|
|
aw ec2 authorize-security-group-ingress --group-id "$internal_sg" --ip-permissions \
|
|
"[{\"IpProtocol\":\"-1\",\"IpRanges\":[{\"CidrIp\":\"$internal_cidr\",\"Description\":\"Redes privadas do laboratorio\"}]}]" >/dev/null
|
|
done
|
|
done
|
|
# Encaminhamento persistente, sem depender de download de pacotes.
|
|
local gateway_user_data='#cloud-config
|
|
write_files:
|
|
- path: /etc/sysctl.d/90-vpn-lab.conf
|
|
permissions: "0644"
|
|
content: |
|
|
net.ipv4.ip_forward=1
|
|
runcmd:
|
|
- [sysctl, --system]
|
|
'
|
|
local disk="[{\"DeviceName\":\"$root_device\",\"Ebs\":{\"VolumeSize\":8,\"VolumeType\":\"gp3\",\"DeleteOnTermination\":true,\"Encrypted\":true}}]"
|
|
gateway=$(aw ec2 run-instances --image-id "$ami" --instance-type "$INSTANCE_TYPE" --count 1 \
|
|
--key-name "$KEY_NAME" --subnet-id "$public_subnet" --private-ip-address 10.20.1.10 \
|
|
--security-group-ids "$gateway_sg" --no-associate-public-ip-address \
|
|
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
|
|
--block-device-mappings "$disk" --user-data "$gateway_user_data" \
|
|
--tag-specifications "$(tags instance gateway)" "$(tags volume gateway)" \
|
|
--client-token "$vpc-gateway" --query 'Instances[0].InstanceId' --output text)
|
|
record GatewayInstanceId "$gateway"
|
|
aw ec2 wait instance-running --instance-ids "$gateway"
|
|
aw ec2 modify-instance-attribute --instance-id "$gateway" --no-source-dest-check
|
|
local return_rt return_cidr
|
|
for return_rt in "$public_rt" "$private_rt"; do
|
|
for return_cidr in "$LOCAL_CIDR" "$VPN_CIDR"; do
|
|
aw ec2 create-route --route-table-id "$return_rt" --destination-cidr-block "$return_cidr" \
|
|
--instance-id "$gateway" >/dev/null
|
|
done
|
|
done
|
|
# Registrar a alocacao antes da associacao permite recuperar uma falha parcial.
|
|
local eip_allocation eip_association eip_target public_ip
|
|
eip_allocation=$(aw ec2 allocate-address --domain vpc --query AllocationId --output text)
|
|
record ElasticIpAllocationId "$eip_allocation"
|
|
aw ec2 create-tags --resources "$eip_allocation" \
|
|
--tags "Key=Lab,Value=$LAB_NAME" "Key=Name,Value=$LAB_NAME-gateway"
|
|
public_ip=$(aw ec2 describe-addresses --allocation-ids "$eip_allocation" --query 'Addresses[0].PublicIp' --output text)
|
|
record GatewayPublicIp "$public_ip"
|
|
eip_association=$(aw ec2 associate-address --allocation-id "$eip_allocation" \
|
|
--instance-id "$gateway" --no-allow-reassociation --query AssociationId --output text)
|
|
record ElasticIpAssociationId "$eip_association"
|
|
eip_target=$(aw ec2 describe-addresses --allocation-ids "$eip_allocation" --query 'Addresses[0].InstanceId' --output text)
|
|
[[ "$eip_target" == "$gateway" ]] || { echo 'Elastic IP nao associado ao gateway esperado.' >&2; return 1; }
|
|
server=$(aw ec2 run-instances --image-id "$ami" --instance-type "$INSTANCE_TYPE" --count 1 \
|
|
--key-name "$KEY_NAME" --subnet-id "$private_subnet" --private-ip-address 10.20.2.10 \
|
|
--security-group-ids "$services_sg" --no-associate-public-ip-address \
|
|
--metadata-options HttpTokens=required,HttpEndpoint=enabled --block-device-mappings "$disk" \
|
|
--tag-specifications "$(tags instance servicos)" "$(tags volume servicos)" \
|
|
--client-token "$vpc-servicos" --query 'Instances[0].InstanceId' --output text)
|
|
record ServicesInstanceId "$server"
|
|
aw ec2 wait instance-running --instance-ids "$server"
|
|
local private_public_ip
|
|
private_public_ip=$(aw ec2 describe-instances --instance-ids "$server" --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
|
|
[[ "$private_public_ip" == None || -z "$private_public_ip" ]] || { echo 'Servidor privado recebeu IP publico inesperado.' >&2; return 1; }
|
|
if [[ "$create_key" == true ]]; then
|
|
local ssh_config="$state_dir/${LAB_NAME}-$run_id.ssh-config"
|
|
cat > "$ssh_config" <<EOF
|
|
Host lab-gateway
|
|
HostName $public_ip
|
|
User ubuntu
|
|
IdentityFile "$key_file"
|
|
IdentitiesOnly yes
|
|
Host lab-servicos
|
|
HostName 10.20.2.10
|
|
User ubuntu
|
|
IdentityFile "$key_file"
|
|
IdentitiesOnly yes
|
|
ProxyCommand ssh -F "$ssh_config" -W %h:%p lab-gateway
|
|
EOF
|
|
record SshConfigFile "$ssh_config"
|
|
printf 'Acesso pelo terminal atual:\n ssh -F %q lab-gateway\n ssh -F %q lab-servicos\n' "$ssh_config" "$ssh_config"
|
|
echo 'Guarde uma copia privada do arquivo .pem antes de perder acesso a este terminal.'
|
|
fi
|
|
cat <<EOF
|
|
Infraestrutura criada. Diario: $STATE_FILE
|
|
Gateway: ubuntu@$public_ip | Servidor privado: ubuntu@10.20.2.10
|
|
As EC2 estao running; cloud-init e SSH podem levar mais alguns minutos.
|
|
Se usou KEY_NAME preexistente, configure a IdentityFile para ambos os hosts (veja README).
|
|
OpenVPN, certificados, intranet e coleta de logs ainda precisam ser configurados.
|
|
AWS pronta para rede local $LOCAL_CIDR e tunel $VPN_CIDR; use essas faixas no OpenVPN.
|
|
No gateway, apos cloud-init: sysctl net.ipv4.ip_forward deve retornar 1.
|
|
A sub-rede privada nao possui saida para Internet. Veja README para instalar pacotes.
|
|
Elastic IP do gateway: $public_ip (alocacao: $eip_allocation).
|
|
O endereco permanece ao parar/iniciar a instancia enquanto a alocacao e associacao forem mantidas.
|
|
Ao desmontar o laboratorio, desassocie e libere esse Elastic IP para encerrar sua cobranca.
|
|
EOF
|
|
}
|
|
|
|
# Executar somente depois de Bash ter lido a funcao inteira do pipe. |