Article image
Jader Greiner
Jader Greiner26/05/2024 10:10
Share

Criando um Servidor EC2 e um Banco de Dados RDS para WordPress com Terraform

    Neste artigo, vou mostrar como provisionar um servidor EC2 e um banco de dados RDS na AWS para hospedar um site WordPress utilizando Terraform. Vamos criar uma infraestrutura completa, incluindo uma VPC, sub-redes, gateway de Internet, tabelas de roteamento e grupos de segurança.

    O que é Terraform?

    Terraform é uma ferramenta de Infraestrutura como Código (IaC) que permite definir, provisionar e gerenciar recursos de infraestrutura em diversos provedores de nuvem usando uma linguagem de configuração declarativa.

    Infraestrutura a ser Provisionada

    • VPC (Virtual Private Cloud): Rede isolada na AWS onde todos os outros recursos serão provisionados.
    • Sub-redes: Duas sub-redes públicas para distribuir recursos em diferentes zonas de disponibilidade.
    • Internet Gateway: Permite que as instâncias na VPC se comuniquem com a Internet.
    • Tabela de Roteamento: Define como o tráfego será roteado dentro da VPC.
    • Grupos de Segurança: Controla o tráfego de entrada e saída para as instâncias EC2 e o banco de dados RDS.
    • Instância EC2: Servidor onde o WordPress será instalado.
    • Banco de Dados RDS MySQL: Armazenamento dos dados do WordPress.

    Código Terraform

    Provider

    Primeiro, definimos o provedor AWS e a região onde os recursos serão provisionados:

    provider "aws" {
    region = "us-east-2" # Substitua pela região desejada
    }
    

    VPC

    Criamos a VPC com um bloco CIDR de 10.0.0.0/16 e habilitamos suporte a DNS:

    resource "aws_vpc" "main" {
    cidr_block           = "10.0.0.0/16"
    enable_dns_hostnames = true
    enable_dns_support   = true
    tags = {
      Name = "main_vpc"
    }
    }
    

    Sub-redes

    Duas sub-redes públicas são criadas em diferentes zonas de disponibilidade:

    resource "aws_subnet" "main1" {
    vpc_id                  = aws_vpc.main.id
    cidr_block              = "10.0.1.0/24"
    availability_zone       = "us-east-2a"
    map_public_ip_on_launch = true
    
    tags = {
      Name = "main_subnet1"
    }
    }
    
    resource "aws_subnet" "main2" {
    vpc_id                  = aws_vpc.main.id
    cidr_block              = "10.0.2.0/24"
    availability_zone       = "us-east-2b"
    map_public_ip_on_launch = true
    tags = {
      Name = "main_subnet2"
    }
    }
    

    Internet Gateway e Tabela de Roteamento

    Um gateway de Internet e uma tabela de roteamento são criados e associados às sub-redes:

    resource "aws_internet_gateway" "main" {
    vpc_id = aws_vpc.main.id
    
    tags = {
      Name = "main_igw"
    }
    }
    
    resource "aws_route_table" "main" {
    vpc_id = aws_vpc.main.id
    
    route {
      cidr_block = "0.0.0.0/0"
      gateway_id = aws_internet_gateway.main.id
    }
    
    tags = {
      Name = "main_route_table"
    }
    }
    
    resource "aws_route_table_association" "main1" {
    subnet_id      = aws_subnet.main1.id
    route_table_id = aws_route_table.main.id
    }
    
    resource "aws_route_table_association" "main2" {
    subnet_id      = aws_subnet.main2.id
    route_table_id = aws_route_table.main.id
    }
    

    Grupos de Segurança

    Definimos grupos de segurança para a instância EC2 e o RDS:

    resource "aws_security_group" "ec2_sg" {
    name   = "ec2_security_group"
    vpc_id = aws_vpc.main.id
    
    ingress {
      from_port   = 22
      to_port     = 22
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"] # Permite acesso SSH de qualquer lugar
    }
    
    ingress {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"] # Permite acesso HTTP de qualquer lugar
    }
    
    ingress {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"] # Permite acesso HTTPS de qualquer lugar
    }
    
    ingress {
      from_port   = 8
      to_port     = 0
      protocol    = "icmp"
      cidr_blocks = ["0.0.0.0/0"] # Permite acesso ICMP (ping) de qualquer lugar
    }
    
    egress {
      from_port   = 0
      to_port     = 0
      protocol    = "-1"
      cidr_blocks = ["0.0.0.0/0"] # Permite todo o tráfego de saída
    }
    
    tags = {
      Name = "ec2_security_group"
    }
    }
    
    resource "aws_security_group" "rds_sg" {
    vpc_id = aws_vpc.main.id
    
    ingress {
      from_port   = 3306
      to_port     = 3306
      protocol    = "tcp"
      cidr_blocks = ["10.0.1.0/24"]
    }
    
    egress {
      from_port   = 0
      to_port     = 0
      protocol    = "-1"
      cidr_blocks = ["0.0.0.0/0"]
    }
    
    tags = {
      Name = "rds_security_group"
    }
    }
    

    Instância EC2

    Provisionamos a instância EC2 e configuramos o WordPress:

    data "aws_ami" "ubuntu" {
    most_recent = true
    
    filter {
      name   = "name"
      values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
    }
    
    filter {
      name   = "virtualization-type"
      values = ["hvm"]
    }
    
    owners = ["099720109477"]
    }
    
    resource "aws_instance" "wordpress" {
    ami                         = data.aws_ami.ubuntu.id
    instance_type               = "t2.micro"
    subnet_id                   = aws_subnet.main1.id
    vpc_security_group_ids      = [aws_security_group.ec2_sg.id]
    associate_public_ip_address = true
    
    user_data = <<-EOF
             #!/bin/bash
             apt-get update
             apt-get install -y apache2 ssl-cert
             
             # Configure Apache to listen on port 80 and 443
             cat << 'APACHE_CONFIG' > /etc/apache2/sites-available/default-ssl.conf
             <IfModule mod_ssl.c>
               <VirtualHost *:80>
                 ServerAdmin webmaster@localhost
                 DocumentRoot /var/www/html
                 ErrorLog /var/log/apache2/error.log
                 CustomLog /var/log/apache2/access.log combined
               </VirtualHost>
             
               <VirtualHost *:443>
                 ServerAdmin webmaster@localhost
                 DocumentRoot /var/www/html
                 ErrorLog /var/log/apache2/error.log
                 CustomLog /var/log/apache2/access.log combined
             
                 SSLEngine on
                 SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
                 SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
               </VirtualHost>
             </IfModule>
             APACHE_CONFIG
             
             a2ensite default-ssl
             a2enmod ssl
             systemctl restart apache2
             
             # Install MySQL
             apt-get install -y mysql-server
             systemctl start mysql
             systemctl enable mysql
             
             # Install PHP and extensions
             apt-get install -y php libapache2-mod-php php-mysql
             
             # Download and configure WordPress
             cd /var/www/html
             wget http://wordpress.org/latest.tar.gz
             tar -xzf latest.tar.gz
             chown -R www-data:www-data /var/www/html/wordpress
             find /var/www/html/wordpress/ -type d -exec chmod 750 {} \;
             find /var/www/html/wordpress/ -type f -exec chmod 640 {} \;
             mv wordpress/* .
             rm -rf wordpress
             systemctl restart apache2
             EOF
    
    tags = {
      Name = "Wordpress_Server"
    }
    }
    
    output "wordpress_public_dns" {
    description = "Public DNS of the WordPress EC2 instance"
    value       = aws_instance.wordpress.public_dns
    }
    

    Banco de Dados RDS

    Criamos o banco de dados MySQL no RDS:

    resource "aws_db_instance" "mysql" {
    identifier        = "my-mysql-db"
    engine            = "mysql"
    engine_version    = "8.0"
    instance_class    = "db.t3.micro"
    allocated_storage = 20
    storage_type      = "gp2"
    
    backup_retention_period = 0
    maintenance_window      = "Mon:00:00-Mon:03:00"
    
    db_name              = "wordpressdb"
    username             = "admin"
    password             = "password"
    parameter_group_name = "default.mysql8.0"
    
    vpc_security_group_ids = [aws_security_group.rds_sg.id]
    db_subnet_group_name   = aws_db_subnet_group.main.name
    
    skip_final_snapshot = true
    
    tags = {
      Name = "Wordpress_RDS"
    }
    }
    
    resource "aws_db_subnet_group" "main" {
    name       = "main"
    subnet_ids = [aws_subnet.main1.id, aws_subnet.main2.id]
    
    tags = {
      Name = "main_subnet_group"
    }
    }
    

    Dicas e Recomendações Especiais

    1. Caso de Estudo: Este exemplo é um caso de estudo e não possui todas as configurações de segurança necessárias para um ambiente de produção.
    2. Segurança: Permitir acesso SSH de qualquer lugar (0.0.0.0/0) não é recomendado para ambientes de produção. Restringir o acesso a um intervalo de IPs específico para maior segurança.
    3. Configurações Específicas: No código, algumas configurações são específicas à sua conta, como a região (us-east-2) e os IDs de AMI. Certifique-se de adaptar essas configurações às suas necessidades.
    4. Credenciais: Nunca armazene credenciais diretamente no código. Utilize práticas seguras, como o AWS Secrets Manager ou variáveis de ambiente, para gerenciar suas credenciais.

    Conclusão

    Neste artigo, provisionamos uma infraestrutura completa na AWS para hospedar um site WordPress utilizando Terraform. Criamos uma VPC, sub-redes, gateway de Internet, tabelas de roteamento, grupos de segurança, uma instância EC2 e um banco de dados RDS. Com essa infraestrutura, você está pronto para hospedar seu site WordPress na AWS de forma eficiente e escalável.

    Espero que este guia tenha sido útil. Fique à vontade para deixar comentários e compartilhar suas experiências.

    Código completo abaixo:

    provider "aws" {
     region = "us-east-2" # Substitua pela região desejada
    }
    
    # Criar VPC
    resource "aws_vpc" "main" {
     cidr_block = "10.0.0.0/16"
     # ... other VPC configuration
     enable_dns_hostnames = true
     enable_dns_support  = true
    
     tags = {
    Name = "main_vpc"
     }
    }
    
    # Criar sub-rede 1
    resource "aws_subnet" "main1" {
     vpc_id         = aws_vpc.main.id
     cidr_block       = "10.0.1.0/24"
     availability_zone    = "us-east-2a"
     map_public_ip_on_launch = true
    
    
     tags = {
    Name = "main_subnet1"
     }
    }
    
    # Criar sub-rede 2
    resource "aws_subnet" "main2" {
     vpc_id         = aws_vpc.main.id
     cidr_block       = "10.0.2.0/24"
     availability_zone    = "us-east-2b"
     map_public_ip_on_launch = true
    
    
     tags = {
    Name = "main_subnet2"
     }
    }
    
    # Criar gateway de Internet
    resource "aws_internet_gateway" "main" {
     vpc_id = aws_vpc.main.id
    
     tags = {
    Name = "main_igw"
     }
    }
    
    # Criar tabela de roteamento
    resource "aws_route_table" "main" {
     vpc_id = aws_vpc.main.id
    
     route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
     }
    
     tags = {
    Name = "main_route_table"
     }
    }
    
    # Associar a tabela de roteamento à sub-rede 1
    resource "aws_route_table_association" "main1" {
     subnet_id   = aws_subnet.main1.id
     route_table_id = aws_route_table.main.id
    }
    
    # Associar a tabela de roteamento à sub-rede 2
    resource "aws_route_table_association" "main2" {
     subnet_id   = aws_subnet.main2.id
     route_table_id = aws_route_table.main.id
    }
    
    # Criar grupo de segurança para a instância EC2
    resource "aws_security_group" "ec2_sg" {
     name  = "ec2_security_group"
     vpc_id = aws_vpc.main.id
    
     ingress {
    from_port  = 22
    to_port   = 22
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # Allow SSH access from anywhere (not recommended for production)
     }
    
     ingress {
    from_port  = 80
    to_port   = 80
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # Allow HTTP access from anywhere
     }
    
     ingress {
    from_port  = 443
    to_port   = 443
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # Allow HTTPS access from anywhere
     }
    
     ingress {
    from_port  = 8
    to_port   = 0
    protocol  = "icmp"
    cidr_blocks = ["0.0.0.0/0"] # Allow ICMP (ping) access from anywhere
     }
    
     egress {
    from_port  = 0
    to_port   = 0
    protocol  = "-1"
    cidr_blocks = ["0.0.0.0/0"] # Allow all outbound traffic
     }
    
     tags = {
    Name = "ec2_security_group"
     }
    }
    
    #Terraform Data Block - To Lookup Latest Ubuntu 20.04 AMI Image
    data "aws_ami" "ubuntu" {
     most_recent = true
    
     filter {
    name  = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
     }
    
     filter {
    name  = "virtualization-type"
    values = ["hvm"]
     }
    
     owners = ["099720109477"]
    }
    
    # Criar instância EC2
    resource "aws_instance" "wordpress" {
     ami             = data.aws_ami.ubuntu.id
     instance_type        = "t2.micro" # Elegível para o free tier
     subnet_id          = aws_subnet.main1.id
     vpc_security_group_ids   = [aws_security_group.ec2_sg.id]
     associate_public_ip_address = true
    
     user_data = <<-EOF
        #!/bin/bash
        apt-get update
        apt-get install -y apache2 ssl-cert
        
        # Configure Apache to listen on port 80 and 443
        cat << 'APACHE_CONFIG' > /etc/apache2/sites-available/default-ssl.conf
        <IfModule mod_ssl.c>
         <VirtualHost *:80>
          ServerAdmin webmaster@localhost
          DocumentRoot /var/www/html
          ErrorLog /var/log/apache2/error.log
          CustomLog /var/log/apache2/access.log combined
         </VirtualHost>
        
         <VirtualHost *:443>
          ServerAdmin webmaster@localhost
          DocumentRoot /var/www/html
          ErrorLog /var/log/apache2/error.log
          CustomLog /var/log/apache2/access.log combined
        
          SSLEngine on
          SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
          SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
         </VirtualHost>
        </IfModule>
        APACHE_CONFIG
        
        a2ensite default-ssl
        a2enmod ssl
        systemctl restart apache2
        
        # Install MySQL
        apt-get install -y mysql-server
        systemctl start mysql
        systemctl enable mysql
        
        # Install PHP and extensions
        apt-get install -y php libapache2-mod-php php-mysql
        
        # Download and configure WordPress
        cd /var/www/html
        wget http://wordpress.org/latest.tar.gz
        tar -xzf latest.tar.gz
        chown -R www-data:www-data /var/www/html/wordpress
        find /var/www/html/wordpress/ -type d -exec chmod 750 {} \;
        find /var/www/html/wordpress/ -type f -exec chmod 640 {} \;
        mv wordpress/* .
        rm -rf wordpress
        systemctl restart apache2
        EOF
    
    
    
     tags = {
    Name = "Wordpress_Server"
     }
    
    }
    
    output "wordpress_public_dns" {
     description = "Public DNS of the WordPress EC2 instance"
     value    = aws_instance.wordpress.public_dns
    }
    
    # Criar grupo de segurança para o RDS
    resource "aws_security_group" "rds_sg" {
     vpc_id = aws_vpc.main.id
    
     ingress {
    from_port  = 3306
    to_port   = 3306
    protocol  = "tcp"
    cidr_blocks = ["10.0.1.0/24"]
     }
    
     egress {
    from_port  = 0
    to_port   = 0
    protocol  = "-1"
    cidr_blocks = ["0.0.0.0/0"]
     }
    
     tags = {
    Name = "rds_security_group"
     }
    }
    
    
    # Criar banco de dados RDS MySQL
    resource "aws_db_instance" "mysql" {
     identifier    = "my-mysql-db"
     engine      = "mysql"
     engine_version  = "8.0"     # Versão compatível com db.t3.micro
     instance_class  = "db.t3.micro" # Elegível para o free tier
     allocated_storage = 20
     storage_type   = "gp2"
    
     # Remove backup configuration
     backup_retention_period = 0           # Set backup retention period to 0 to disable automated backups
     backup_window      = ""          # Clear the backup window
     maintenance_window   = "Mon:00:00-Mon:03:00" # Keep the maintenance window
    
     db_name       = "wordpressdb"
     username       = "admin"
     password       = "password"
     parameter_group_name = "default.mysql8.0"
    
     vpc_security_group_ids = [aws_security_group.rds_sg.id]
     db_subnet_group_name  = aws_db_subnet_group.main.name
    
     skip_final_snapshot = true
    
    
     tags = {
    Name = "Wordpress_RDS"
     }
    }
    
    # Criar grupo de sub-rede do RDS
    resource "aws_db_subnet_group" "main" {
     name    = "main"
     subnet_ids = [aws_subnet.main1.id, aws_subnet.main2.id]
    
     tags = {
    Name = "main_subnet_group"
     }
    }
    
    Share
    Comments (0)