Showing posts with label AWS. Show all posts
Showing posts with label AWS. Show all posts

Saturday, 22 March 2025

Overview of IAM (Identity and Access Management) in AWS

 Below is a comprehensive overview of IAM (Identity and Access Management) in AWS, incorporating the concepts from your previous input, correcting and expanding them, and adding additional knowledge based on standard AWS IAM practices. This response aims to provide a complete understanding of IAM, including its components, features, tools, best practices, and more, as of my knowledge base (continuously updated through March 22, 2025). I’ve organized it into clear sections for ease of understanding.


What is IAM?

  • Definition: IAM (Identity and Access Management) is a global AWS service that enables you to manage identities (users, groups, roles) and their access to AWS resources securely.
  • Purpose: Controls "who" (authentication) can do "what" (authorization) in your AWS account.
  • Scope: IAM is global, meaning it applies across all AWS regions without region-specific configuration.

Core Components of IAM

  1. Root Account:
    • Created by default when you set up an AWS account.
    • Has full access to all AWS services and resources.
    • Secured with an email address and password.
    • Best Practice: Avoid using it for daily tasks; enable MFA and use it only for initial setup.
  2. IAM Users:
    • Represent individuals or applications requiring access to AWS.
    • Each user has a unique name and can have credentials (password for console, access keys for programmatic access).
    • Users can be assigned permissions directly or through groups.
  3. IAM Groups:
    • Collections of IAM users (cannot contain other groups).
    • Simplify permission management by assigning policies to groups rather than individual users.
    • Example: A "Developers" group with access to EC2 and S3.
  4. IAM Policies:
    • JSON documents defining permissions (what actions are allowed or denied on which resources).
    • Types:
      • Managed Policies: AWS-managed (e.g., AmazonS3ReadOnlyAccess) or customer-managed (custom policies).
      • Inline Policies: Embedded directly into a user, group, or role (less reusable).
    • Structure:
      { "Version": "2012-10-17", "Statement": [ { "Sid": "S3ReadOnly", "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*" } ] }
  5. IAM Roles:
    • Temporary identities with permissions that AWS entities (e.g., services, users, or external identities) can assume.
    • Unlike users, roles don’t have permanent credentials; they use temporary security tokens.
    • Use Cases:
      • AWS services (e.g., EC2 accessing S3).
      • Cross-account access.
      • Federation (e.g., SAML, OIDC).
  6. Permissions:
    • Defined in policies and assigned to users, groups, or roles.
    • Follow the Principle of Least Privilege: Grant only the minimum permissions needed.

Key IAM Features

  1. Authentication:
    • Verifies "who" is accessing AWS.
    • Methods:
      • Console: Username + password (+ MFA).
      • Programmatic: Access Key ID + Secret Access Key (+ MFA).
  2. Authorization:
    • Determines "what" an authenticated identity can do.
    • Controlled via policies specifying actions, resources, and conditions.
  3. Multi-Factor Authentication (MFA):
    • Adds a second layer of security (e.g., authenticator app, hardware token).
    • Supported MFA types: Virtual MFA (e.g., Google Authenticator), U2F, hardware MFA.
    • Best Practice: Enable MFA for all users, especially the root account.
  4. Password Policy:
    • Customizable rules for IAM user passwords.
    • Examples: Minimum length, require numbers/special characters, password expiration.
  5. Access Keys:
    • Used for programmatic access (CLI, SDK, APIs).
    • Consist of:
      • Access Key ID: Public identifier (e.g., AKIA...).
      • Secret Access Key: Private key (kept secret).
    • Best Practice: Rotate keys regularly and delete unused keys.
  6. Temporary Security Credentials:
    • Provided via IAM roles or AWS Security Token Service (STS).
    • Include Access Key ID, Secret Access Key, and a session token.
    • Expiration: Configurable (15 minutes to 36 hours).

IAM Policy Details

  1. Policy Structure:
    • Version: Policy language version (e.g., "2012-10-17").
    • ID: Optional unique identifier.
    • Statement: Array of permission rules (required).
  2. Statement Elements:
    • Sid (Statement ID): Optional identifier for readability.
    • Effect: "Allow" or "Deny".
    • Principal: Entity affected (e.g., "*" for all, or specific ARN).
    • Action: AWS service actions (e.g., "s3:PutObject", "iam:*" for all IAM actions).
    • Resource: ARN of the resource (e.g., "arn:aws:s3:::my-bucket/*").
    • Condition: Optional rules (e.g., "aws:SourceIp": "203.0.113.0/24").
  3. Policy Evaluation Logic:
    • Default: Implicit deny (no access unless explicitly allowed).
    • Explicit "Allow" in a policy grants access.
    • Explicit "Deny" overrides any "Allow".
    • Combined policies (e.g., from multiple groups) are evaluated together.

Hands-On Processes

  1. Creating Users:
    • AWS Console:
      • Navigate to IAM > Users > Add User.
      • Enter username, select access type (console, programmatic, or both).
      • Set password (custom or auto-generated).
      • Assign permissions (direct or via groups).
      • Add tags (optional).
  2. Creating Groups:
    • IAM > Groups > Create Group.
    • Name the group, attach policies, and add users.
  3. Creating Policies:
    • IAM > Policies > Create Policy.
    • Use Visual Editor or JSON editor to define permissions.
    • Example:
      json
      { "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "ec2:Describe*", "Resource": "*" } }
  4. Creating Roles:
    • IAM > Roles > Create Role.
    • Select trusted entity (e.g., AWS service like EC2).
    • Attach policies and name the role.
  5. CLI Setup:
    • Install AWS CLI (awscli package).
    • Run:
      bash
      aws configure
      • Enter Access Key ID, Secret Access Key, region, output format.
    • Test: aws iam list-users.
  6. MFA Setup:
    • IAM > Users > Select User > Security Credentials > Assign MFA Device.
    • Scan QR code with an authenticator app or enter hardware MFA details.

IAM Tools

  1. AWS CLI:
    • Command-line tool for managing AWS services.
    • Example: aws iam create-user --user-name Alice.
  2. AWS SDK:
    • Libraries for programmatic access (e.g., Boto3 for Python).
    • Example (Python):
      python
      import boto3 iam = boto3.client('iam') iam.create_user(UserName='Bob')
  3. AWS CloudShell:
    • Browser-based CLI in the AWS Console.
    • Pre-authenticated; no local setup required.
  4. IAM Credential Report:
    • CSV report listing all users and their credential status (e.g., MFA, access keys).
    • IAM > Credential Report > Download.
  5. IAM Access Advisor:
    • Shows permissions granted to a user and last-accessed timestamps for services.
    • IAM > Users > Select User > Access Advisor.

IAM Security and Best Practices

  1. Security Features:
    • MFA for enhanced authentication.
    • Password policies for strong credentials.
    • Temporary credentials via roles/STs.
  2. Best Practices:
    • Lock down the root account (use only for setup, enable MFA).
    • Create individual IAM users for each person/application.
    • Use groups for permission management.
    • Apply least privilege in policies.
    • Enable MFA for all users.
    • Use roles for AWS services and cross-account access.
    • Rotate access keys regularly.
    • Monitor and audit with IAM tools.

Shared Responsibility Model

  1. AWS Responsibilities:
    • Secure global infrastructure.
    • IAM service availability and security.
    • Compliance certifications (e.g., SOC, ISO).
  2. Your Responsibilities:
    • Manage IAM entities (users, groups, roles, policies).
    • Secure credentials (passwords, keys, MFA).
    • Define and enforce access policies.
    • Monitor and audit IAM usage.

Advanced IAM Concepts

  1. Federation:
    • Integrate with external identity providers (e.g., SAML, OIDC).
    • Allows single sign-on (SSO) with corporate credentials.
  2. IAM Permissions Boundaries:
    • Limit the maximum permissions a user or role can have.
    • Example: Restrict an admin role to specific services.
  3. Service Control Policies (SCPs):
    • Used with AWS Organizations to set permission guardrails across accounts.
    • Not part of IAM directly but complements it.
  4. Tagging:
    • Attach metadata (key-value pairs) to IAM entities for organization and cost allocation.
    • Example: Environment=Production.

IAM Summary

  • Users: Individuals or apps with credentials (passwords, keys).
  • Groups: Organize users for bulk permission assignment.
  • Policies: JSON documents defining permissions.
  • Roles: Temporary permissions for AWS services or federation.
  • Security: MFA, password policies, key rotation.
  • Tools: CLI, SDK, CloudShell, Credential Reports, Access Advisor.
  • Goal: Securely manage access while adhering to least privilege.

This is a complete and corrected compilation of IAM knowledge, blending your original input with additional AWS-standard concepts. If you’d like examples (e.g., JSON policies, CLI commands, or Python code with Boto3), or a deeper dive into any section, let me know!

Thursday, 12 December 2024

Set up a single EC2 instance running Nginx as a load balancer and SSL terminator using Let’s Encrypt

How to set up a single EC2 instance running Nginx as a load balancer and SSL terminator using Let’s Encrypt, directing traffic to three EC2 instances running a Laravel application. This guide assumes a standard AWS VPC environment and that you have control over DNS records for your domain.

Overview of the Architecture

  • Public-facing EC2 (Load Balancer):
    • Runs Nginx.
    • Terminates SSL using Let’s Encrypt certificates.
    • Proxies requests to the 3 backend Laravel application servers.
  • Three Backend EC2 Instances (Laravel App Servers):
    • Run Laravel (with PHP-FPM, Nginx, or Apache).
    • Accessible only within the same VPC, ideally in private subnets.
    • The load balancer communicates with them via private IP addresses.

Prerequisites

  1. AWS Setup:

    • A VPC with subnets. Assume:
      • One public subnet for the load balancer EC2.
      • Private subnets for the Laravel app servers.
    • Security groups properly set up so the load balancer can access the app servers on port 80 (or your chosen port).
  2. EC2 Instances:

    • Load Balancer EC2:
      • Public subnet.
      • Has a public IP or an Elastic IP (EIP) so it’s reachable from the internet.
    • Laravel App EC2s:
      • Typically in private subnets (recommended) or can be public if properly secured.
      • Each running a web server (Nginx/Apache) and PHP-FPM, serving the Laravel app on port 80 internally.
    • Ensure that DNS (e.g., example.com) points to the public IP of the load balancer EC2.
  3. DNS Configuration:

    • In your domain registrar or DNS provider, create an A record for example.com pointing to the load balancer EC2’s public IP.
    • If using a subdomain (e.g., app.example.com), point that subdomain to the load balancer.

Step-by-Step Setup

A. Set Up the Backend Laravel Instances

  1. Install and Run Laravel:

    • On each Laravel EC2 instance, ensure:
      • PHP, Composer, and a web server (Nginx or Apache) are installed.
      • The Laravel code is deployed in /var/www/html or a similar directory.
      • Nginx or Apache is configured to serve the application at http://localhost:80.
    • Test locally on each instance:
      bash
      curl http://localhost
      You should see the Laravel default page or your application’s output.
  2. Security Groups (Backend):

    • The backend servers’ security group should allow inbound traffic on port 80 only from the load balancer’s private IP or security group, not from the public internet.
    • Outbound traffic is usually unrestricted by default.

B. Set Up the Load Balancer EC2 (Nginx + Let’s Encrypt)

  1. Install Nginx: On a Ubuntu-based system:

    bash
    sudo apt-get update sudo apt-get install nginx -y

    Confirm Nginx is running:

    bash
    systemctl status nginx
  2. Open Ports in Security Group (Load Balancer):

    • Inbound: allow HTTP (80) and HTTPS (443) from 0.0.0.0/0 so the public can access the site.
    • Outbound: allow traffic to the backend servers on port 80.
  3. Configure Nginx Upstream for Load Balancing: Create an upstream configuration file:

    bash
    sudo nano /etc/nginx/conf.d/upstream.conf

    Add:

    nginx
    upstream laravel_app { server 10.0.1.10:80; # Private IP of Laravel app server 1 server 10.0.1.11:80; # Private IP of Laravel app server 2 server 10.0.1.12:80; # Private IP of Laravel app server 3 }

    Replace IPs with the actual private IPs of your Laravel servers.

  4. Create Nginx Server Block for HTTP:

    bash
    sudo nano /etc/nginx/sites-available/example.com

    Add:

    nginx
    server { listen 80; server_name example.com www.example.com; # Location for Let's Encrypt HTTP-01 challenge location /.well-known/acme-challenge/ { root /var/www/html; } # Proxy pass to backend location / { proxy_pass http://laravel_app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

    Create the root directory for Let’s Encrypt challenges (if it doesn't exist):

    bash
    sudo mkdir -p /var/www/html/.well-known/acme-challenge sudo chown -R www-data:www-data /var/www/html

    Enable the site:

    bash
    sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx

    Now http://example.com should route to one of the backend Laravel servers. Test by visiting http://example.com.

C. Obtain and Install Let’s Encrypt SSL Certificate

  1. Install Certbot: On Ubuntu:

    bash
    sudo apt-get install certbot python3-certbot-nginx -y
  2. Run Certbot:

    bash
    sudo certbot --nginx -d example.com -d www.example.com

    Certbot will:

    • Place a challenge file in /.well-known/acme-challenge/ for domain verification.
    • Request an SSL certificate from Let’s Encrypt.
    • Update the Nginx configuration automatically to use HTTPS.
  3. Check the Nginx Configuration After Certbot: After Certbot finishes, it should create or update the example.com config to:

    • Redirect http:// to https://
    • Use ssl_certificate and ssl_certificate_key directives pointing to your Let’s Encrypt certificates.

    A typical final config might look like:

    nginx
    server { listen 80; server_name example.com www.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_pass http://laravel_app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

    Test:

    bash
    sudo nginx -t sudo systemctl reload nginx

    Now, https://example.com should serve the Laravel app over HTTPS.

D. Verify Load Balancing and SSL

  • Open https://example.com in a browser.
  • Confirm the SSL certificate is valid and secured (lock icon in the browser).
  • Refresh multiple times to ensure requests are distributed across the three backend servers (you can check logs on each server to confirm hits).

E. Certificate Renewal

  • Certbot sets up a systemd timer or cron job to auto-renew certificates.
  • Check:
    bash
    systemctl list-timers | grep certbot
    This ensures your SSL certificate is renewed automatically.

F. Additional Considerations

  1. Sticky Sessions / Session Storage: If your Laravel application uses session data (e.g., user logins), consider using a centralized session store such as Redis or a database. Without this, different requests may land on different app servers and cause issues if each server stores sessions locally. Configure SESSION_DRIVER in .env accordingly.

  2. Health Checks & Failover: Consider enabling health checks to ensure Nginx only routes requests to healthy backend servers. You can configure proxy_next_upstream or a specific health check endpoint.

  3. Logging and Monitoring:

    • Nginx logs:
      • Access logs: /var/log/nginx/access.log
      • Error logs: /var/log/nginx/error.log
    • Laravel logs on backend servers:
      Check storage/logs/laravel.log to ensure the requests are being served correctly.
  4. Scaling: If you need more backend servers in the future, just add their IPs to the upstream block and reload Nginx. This makes the system scalable.

Summary:

  • You set up an EC2 instance as a load balancer with Nginx and obtained an SSL certificate from Let’s Encrypt.
  • You pointed your domain name to the load balancer, which then routes traffic to three backend Laravel servers.
  • The setup terminates SSL at the load balancer and distributes requests over HTTP to the Laravel servers internally.
  • With proper DNS, security groups, and upstream configuration, you have a secure, load-balanced environment for your Laravel application.

Thank you

Send emails using Amazon SES with an IAM role

Allowing a Laravel application, running on an EC2 instance in a public subnet, to send emails using Amazon SES with an IAM role:

1. Prerequisites and Overvie

Before configuring your application, ensure that:

  • SES Setup:
    You have verified your sending domain or email address in Amazon SES. If your account is still in the SES sandbox, you need to verify every recipient email address as well. Once moved out of the sandbox by requesting production access, you can send to any email address.

  • Region Selection:
    SES is a regional service. Make sure you use the same region for SES and the IAM role policies. Also, ensure that your .env and mail configuration files in Laravel reflect the correct region.

2. Create and Attach an IAM Role with SES Permissions

Instead of manually providing AWS credentials in .env, you can rely on an IAM role attached to the EC2 instance. The AWS SDK in Laravel will automatically retrieve temporary credentials from the instance metadata:

  1. Create the IAM Role:

    • Open the IAM console in AWS.
    • Click Roles > Create role.
    • Select AWS service and choose EC2 as the use case.
    • Click Next: Permissions.
    • Attach a policy that allows sending emails via SES. For testing, you can use AmazonSESFullAccess (not recommended for production), or create a more restrictive policy like:
      json
      { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ses:SendEmail", "ses:SendRawEmail" ], "Resource": "*" } ] }
    • Complete the role creation.
  2. Attach the Role to Your EC2 Instance:

    • Go to the EC2 console and select your running instance.
    • Choose Actions > Security > Modify IAM Role.
    • Select the IAM role you just created and attach it.

After this step, the EC2 instance will have permission to send emails through SES without requiring access keys in the application’s code.

3. Configure Laravel to Use SES

Laravel uses config/mail.php and .env for mail configurations. The SES mailer is built into Laravel’s core mail system (for Laravel versions 5.7+):

  1. .env Configuration: In your .env, specify SES as your mail driver and the AWS region:

    env
    MAIL_MAILER=ses AWS_DEFAULT_REGION=us-east-1 # or your chosen region AWS_SES_REGION=us-east-1 # match the region where your SES is set up # Leave these blank since the IAM role will provide credentials: AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY=

    Note: The AWS_SES_REGION should correspond to the region where your SES service (domain/email verification) is set up.

  2. config/mail.php: The default configuration for the SES mailer in config/mail.php might look like this:

    php
    'mailers' => [ 'ses' => [ 'transport' => 'ses', 'region' => env('AWS_SES_REGION', 'us-east-1'), ], // other mailers... ],

    The AWS SDK will automatically fetch credentials from the EC2 instance metadata since the IAM role is attached. You do not need to hardcode any keys.

4. Network and Security Considerations

  • Since the EC2 instance is in a public subnet with an Internet Gateway, it likely already has outbound internet access.
  • Ensure the instance’s Security Group allows outbound HTTPS (port 443) traffic. SES endpoints are accessed over HTTPS.
  • No need for a VPC endpoint if you are fine with public internet access. If you prefer private connectivity and do not want public internet traffic, you would consider adding a VPC endpoint. However, in a public subnet scenario, this is usually unnecessary.

5. Test the Configuration

After setting everything up, test sending an email from your Laravel application:

php
use Illuminate\Support\Facades\Mail; Mail::raw('This is a test email sent via SES', function ($message) { $message->to('recipient@example.com') ->subject('Test SES Email'); });
  • Check the logs at storage/logs/laravel.log if the email is not delivered.
  • If in the SES sandbox, ensure you verify both the sender and recipient addresses.
  • If you see errors related to Unverified email address or MessageRejected, verify that SES is configured correctly and that the email/domain is verified.

6. Common Troubleshooting Tips

  • Permissions: Make sure the IAM role has the correct SES permissions. Check IAM > Roles to confirm the attached policies.
  • Region Mismatch: Ensure the AWS_SES_REGION and the region where you verified your domain in SES match.
  • Sandbox vs. Production: If still in the SES sandbox, you must verify recipient emails. To lift sandbox restrictions, request production access from the AWS SES console.
  • Logging and Debugging:
    Check laravel.log for detailed error messages.
    You can also SSH into the instance and use the AWS CLI to test SES sending (if CLI is installed and configured to use the IAM role):
    bash
    aws ses send-email \ --from sender@verifieddomain.com \ --destination "ToAddresses=recipient@example.com" \ --message "Subject={Data=Test},Body={Text={Data=Test message}}"
    If this works, then the issue might be within the Laravel configuration. If this fails, the problem is at the IAM or SES level.

Summary

  • Assign an IAM role with SES permissions to your EC2 instance.
  • Configure Laravel’s .env and config/mail.php to use SES.
  • Ensure that SES domain/email verification and region alignment are correct.
  • Check networking to confirm outbound HTTPS is allowed.
  • Test sending emails and troubleshoot as necessary.

Thank you

Laravel application hosted on an EC2 instance in a public subnet to access S3

How to allow your Laravel application, running on an EC2 instance in a public subnet, to access S3 using an IAM role:

1. Attach an IAM Role to the EC2 Instance

Instead of hardcoding AWS credentials, you should use an IAM role. This allows the EC2 instance to receive temporary credentials automatically from the AWS metadata service, which is more secure and easier to maintain.

Steps to create and attach an IAM Role:

  1. Create the IAM Role:

    • Go to the IAM section in the AWS Management Console.
    • Click Roles > Create role.
    • Select AWS service as the trusted entity and choose EC2.
    • Click Next: Permissions and attach an appropriate policy for S3 access, for example, AmazonS3FullAccess or a custom policy.
    • Give your role a name and complete the creation process.
  2. Custom Policy Example (Read/Write to a Specific Bucket):

    json
    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::your-bucket-name/*" } ] }
  3. Attach the IAM Role to Your EC2 Instance:

    • Go to the EC2 Dashboard, select the instance that runs your Laravel application.
    • Click Actions > Security > Modify IAM Role.
    • Select the IAM role you created and attach it.

After attaching the IAM role, your EC2 instance will automatically have the necessary permissions to interact with S3 according to the policies you attached. You do not need to store or hardcode credentials on the server.

2. Configure Laravel to Use S3

Your Laravel application needs to know how to use S3 as a storage disk. This is configured in config/filesystems.php.

Update your .env file:

env
AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=your-region AWS_BUCKET=your-bucket-name

Since you’re using an IAM role, you can leave AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY empty. The AWS SDK will fetch temporary credentials from the EC2 instance’s metadata endpoint automatically.

Update config/filesystems.php:

php
's3' => [ 'driver' => 's3', 'key' => env('AWS_ACCESS_KEY_ID'), // leave empty for IAM role 'secret' => env('AWS_SECRET_ACCESS_KEY'), // leave empty for IAM role 'region' => env('AWS_DEFAULT_REGION', 'your-region'), 'bucket' => env('AWS_BUCKET', 'your-bucket-name'), ],

3. Network and Security Configuration

Since your EC2 instance is in a public subnet, ensure it can access the internet:

  • If your EC2 instance is associated with a public subnet that has an Internet Gateway, it likely already has outbound internet access.
  • If you were in a private subnet scenario, you would need a NAT Gateway or a similar setup.

Also, ensure the instance’s Security Group allows outbound traffic over HTTPS (port 443) to reach S3.

4. Test the Setup

You can test your setup within your Laravel application using the Storage facade:

php
use Illuminate\Support\Facades\Storage; // Example: Upload a test file to S3 Storage::disk('s3')->put('test.txt', 'This is a test file!');

If the file successfully appears in your S3 bucket, the configuration is working correctly.

Optional: Troubleshooting

  • Check that the IAM role has the correct permissions for the desired actions.
  • Review the Laravel logs (storage/logs/laravel.log) to see if any errors appear.
  • SSH into the EC2 instance and use the AWS CLI to test access:
    bash
    aws s3 ls s3://your-bucket-name

If you can list the bucket contents from the EC2 instance, it confirms that the instance has the proper credentials and network connectivity.

Summary:
By using an IAM role, you avoid hardcoding credentials. Laravel and the AWS SDK will automatically use the credentials provided by the EC2 instance’s metadata service. Ensure proper permissions, network access, and configuration in filesystems.php and .env. Then test by uploading or retrieving files from S3 via the Storage facade.

Note: You only need to create a VPC S3 endpoint if your EC2 instance does not have direct outbound internet access and you want it to access S3 privately within the VPC. Here are some scenarios:

  • If your EC2 instance is in a public subnet with a working Internet Gateway and can reach the internet (i.e., it has a public IP and Security Group rules allow outbound traffic):
    You do not need a VPC S3 endpoint. The instance can communicate with S3 over the public internet.

  • If your EC2 instance is in a private subnet without internet access (no NAT Gateway or outbound internet route):
    You will need a VPC S3 endpoint. This endpoint allows your EC2 instance to access S3 using private connectivity within AWS, without exposing traffic to the public internet.

So, the decision depends on your networking setup. If you already have internet access or a NAT Gateway for outbound traffic, you don’t need the endpoint. If you want to keep your traffic completely internal and not rely on public internet access, then setting up a VPC endpoint for S3 is the right approach.

Thank you.

Sunday, 1 December 2024

Build server laravel using EC2 in AWS

Building a system for your Laravel application on AWS involves several steps, including configuring your VPC, launching EC2 instances, setting up MySQL and Redis, configuring security, and deploying the application. Here's a comprehensive guide to set up a full Laravel application system on AWS with a custom load balancer:

Step-by-Step Guide: Building a Laravel Application System on AWS


1. Set Up the VPC (Virtual Private Cloud)

The first step is to create a Virtual Private Cloud (VPC) where all your AWS resources will reside.

Create the VPC

  1. Navigate to the VPC Dashboard:

    • In the AWS Management Console, go to Services → VPC.
  2. Create VPC:

    • Click Create VPC.
    • For IPv4 CIDR block, choose something like 10.0.0.0/16.
    • For IPv6 CIDR block, choose No IPv6 CIDR Block unless you need IPv6.
    • Set Tenancy to Default (unless you need dedicated instances).
    • Name your VPC (e.g., laravel-vpc).
  3. Create Subnets:

    • Create at least two subnets:
      • Public Subnet (e.g., 10.0.1.0/24) for your load balancer and web server (Laravel).
      • Private Subnet (e.g., 10.0.2.0/24) for MySQL and Redis.
  4. Create an Internet Gateway:

    • Go to Internet Gateways and click Create Internet Gateway.
    • Attach it to your VPC (laravel-vpc).
  5. Route Tables:

    • Create and associate route tables for both public and private subnets:
      • Public Route Table should have a route to the Internet Gateway.
      • Private Route Table should have no route to the internet (for internal communication).

2. Set Up EC2 Instances

You’ll need to launch several EC2 instances, including the load balancer, Laravel application instances, MySQL, and Redis.

Launch EC2 Instance for Load Balancer (Optional)

If you want to create a custom load balancer using EC2 (instead of AWS ALB):

  1. Launch EC2 Instance for Load Balancer:

    • Go to EC2 Dashboard → Launch Instance.
    • Choose an AMI (e.g., Amazon Linux 2 or Ubuntu).
    • Choose an instance type (e.g., t2.micro for testing).
    • Set security group rules to allow HTTP (80)HTTPS (443), and SSH (22) from trusted IPs.
  2. Install and Configure Load Balancer Software (e.g., Nginx or HAProxy):

    • SSH into the instance and install a reverse proxy like Nginx or HAProxy.
      • Example for Nginx:
        bash
        sudo yum install -y nginx sudo systemctl start nginx sudo systemctl enable nginx
    • Configure it to load balance between your backend Laravel instances.

Launch EC2 Instances for Laravel Application

  1. Launch Two EC2 Instances for Laravel:

    • These will run your Laravel application and handle incoming traffic.
    • Follow the same steps as for the load balancer, but choose the public subnet for these instances.
    • Set security group rules to allow HTTP (80) and HTTPS (443) from your load balancer's IP or security group.
  2. Install Laravel Dependencies:

    • SSH into the Laravel EC2 instances and install PHP, Composer, and other dependencies:
      bash
      sudo yum update -y sudo yum install -y httpd php php-mysqlnd php-mbstring php-xml composer
    • Clone your Laravel project from your Git repository or upload the project files.
  3. Configure Apache/Nginx:

    • Set up Apache or Nginx to serve your Laravel app.
  4. Configure Laravel Environment:

    • Update the .env file in Laravel with your MySQL and Redis configurations:
      env
      DB_CONNECTION=mysql DB_HOST=private-ip-of-mysql DB_PORT=3306 DB_DATABASE=your_database DB_USERNAME=your_user DB_PASSWORD=your_password REDIS_HOST=private-ip-of-redis REDIS_PASSWORD=null REDIS_PORT=6379

Launch EC2 Instance for MySQL Database

  1. Launch EC2 Instance for MySQL:

    • Choose an Ubuntu or Amazon Linux 2 AMI for MySQL.
    • Assign it to the private subnet.
    • Set security group rules to only allow access from your Laravel instances (on port 3306).
  2. Install MySQL:

    • SSH into the MySQL instance and install MySQL:
      bash
      sudo yum install -y mysql-server sudo systemctl start mysqld sudo systemctl enable mysqld
  3. Create MySQL Database and User:

    • Connect to MySQL:
      bash
      sudo mysql -u root -p
    • Create a database and user:
      sql
      CREATE DATABASE your_database; CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password'; GRANT ALL PRIVILEGES ON your_database.* TO 'your_user'@'%'; FLUSH PRIVILEGES;

Launch EC2 Instance for Redis

  1. Launch EC2 Instance for Redis:

    • Launch another EC2 instance in the private subnet.
    • Set security group rules to allow access to port 6379 only from the Laravel instances.
  2. Install Redis:

    • SSH into the Redis instance and install Redis:
      bash
      sudo yum install -y redis sudo systemctl start redis sudo systemctl enable redis
  3. Configure Redis:

    • Edit the Redis configuration file (/etc/redis/redis.conf) to bind Redis to the private IP and set it to protected mode:
      bash
      bind 127.0.0.1 <private-ip-of-redis> protected-mode yes
  4. Start Redis:

    • Restart Redis to apply the changes:
      bash
      sudo systemctl restart redis

3. Set Up Security Groups

  1. Security Group for Load Balancer:

    • Open HTTP (80) and HTTPS (443) for public access.
    • Allow SSH (22) from trusted IPs for management.
  2. Security Group for Laravel EC2 Instances:

    • Allow HTTP (80) and HTTPS (443) from the load balancer’s security group.
    • Allow MySQL (3306) and Redis (6379) only from the private subnet or specific IPs.
  3. Security Group for MySQL and Redis EC2 Instances:

    • Allow MySQL (3306) from Laravel EC2 instances.
    • Allow Redis (6379) from Laravel EC2 instances.

4. Configure Load Balancer (Optional)

If you're using a custom EC2 instance for load balancing:

  1. Configure the Reverse Proxy (Nginx or HAProxy):
    • Point the reverse proxy to your Laravel EC2 instances.
    • Example for Nginx:
      nginx
      upstream backend { server private-ip-of-laravel-instance1; server private-ip-of-laravel-instance2; } server { listen 80; location / { proxy_pass http://backend; } }

5. Final Testing and Deployment

  1. Test Load Balancer:

    • Access the public IP of your load balancer (if using EC2-based load balancer) or your VPC’s public IP to check if Laravel is working.
  2. Test Database and Redis:

    • Ensure Laravel is able to connect to MySQL and Redis using the configured private IP addresses.
  3. Deploy SSL:

    • If you want to serve your Laravel application over HTTPS, consider setting up SSL on your load balancer or web server (e.g., using Let’s Encrypt for a free SSL certificate).

6. Auto-Scaling and Monitoring

  1. Set Up Auto Scaling:

    • Use AWS Auto Scaling to scale your Laravel EC2 instances based on traffic.
    • Set the desired capacity, minimum, and maximum instances in your Auto Scaling Group.
  2. Set Up Monitoring:

    • Use AWS CloudWatch to monitor the health and performance of your EC2 instances.
    • Set up alarms for key metrics (e.g., CPU usage, memory, disk space).

7. Backup and Security

  1. Backup MySQL:

    • Regularly back up your MySQL database using AWS RDS snapshots or EC2 instance backups.
  2. Ensure Security Best Practices:

    • Use IAM roles for EC2 instances for secure access to AWS services (e.g., S3, Secrets Manager).
    • Enable Multi-AZ for MySQL if using RDS or set up replication for fault tolerance.

Conclusion

This guide takes you through the full process of setting up a Laravel application system on AWS


Code Python

 Full Python Code to Build the System

python
import boto3
import time

# Initialize boto3 clients for EC2, VPC, and IAM
ec2_client = boto3.client('ec2')
vpc_client = boto3.client('ec2')
elb_client = boto3.client('elbv2')
rds_client = boto3.client('rds')
redis_client = boto3.client('elasticache')

# Function to create a VPC
def create_vpc():
    response = vpc_client.create_vpc(
        CidrBlock='10.0.0.0/16',
        InstanceTenancy='default'
    )
    vpc_id = response['Vpc']['VpcId']
    print(f"VPC created: {vpc_id}")
   
    # Create Subnets
    public_subnet = vpc_client.create_subnet(
        VpcId=vpc_id,
        CidrBlock='10.0.1.0/24',
        AvailabilityZone='us-east-1a'
    )
    private_subnet = vpc_client.create_subnet(
        VpcId=vpc_id,
        CidrBlock='10.0.2.0/24',
        AvailabilityZone='us-east-1a'
    )
   
    print(f"Public Subnet: {public_subnet['Subnet']['SubnetId']}")
    print(f"Private Subnet: {private_subnet['Subnet']['SubnetId']}")
   
    # Create Internet Gateway
    igw = vpc_client.create_internet_gateway()
    igw_id = igw['InternetGateway']['InternetGatewayId']
    vpc_client.attach_internet_gateway(
        VpcId=vpc_id,
        InternetGatewayId=igw_id
    )
    print(f"Internet Gateway created and attached: {igw_id}")

    return vpc_id, public_subnet['Subnet']['SubnetId'], private_subnet['Subnet']['SubnetId']

# Function to create EC2 instances
def create_ec2_instances(subnet_id, instance_type, ami_id, key_name, security_group_id):
    instances = ec2_client.run_instances(
        ImageId=ami_id,
        InstanceType=instance_type,
        MinCount=1,
        MaxCount=1,
        KeyName=key_name,
        SubnetId=subnet_id,
        SecurityGroupIds=[security_group_id]
    )
   
    instance_id = instances['Instances'][0]['InstanceId']
    print(f"EC2 instance created: {instance_id}")
    return instance_id

# Function to create a security group
def create_security_group(vpc_id, group_name, description):
    sg = ec2_client.create_security_group(
        GroupName=group_name,
        Description=description,
        VpcId=vpc_id
    )
    security_group_id = sg['GroupId']
    print(f"Security group created: {security_group_id}")
   
    return security_group_id

# Function to create Load Balancer
def create_load_balancer(vpc_id, public_subnet_id):
    response = elb_client.create_load_balancer(
        Name='laravel-load-balancer',
        Subnets=[public_subnet_id],
        SecurityGroups=[],
        Scheme='internet-facing',
        LoadBalancerType='application',
        Listeners=[
            {
                'Protocol': 'HTTP',
                'Port': 80,
                'DefaultActions': [
                    {
                        'Type': 'fixed-response',
                        'FixedResponseConfig': {
                            'StatusCode': 200,
                            'ContentType': 'text/plain',
                            'MessageBody': 'OK'
                        }
                    }
                ]
            }
        ]
    )
    lb_arn = response['LoadBalancers'][0]['LoadBalancerArn']
    print(f"Load balancer created: {lb_arn}")
    return lb_arn

# Function to create RDS MySQL instance
def create_rds_instance():
    response = rds_client.create_db_instance(
        DBInstanceIdentifier='laravel-db',
        DBInstanceClass='db.t2.micro',
        Engine='mysql',
        MasterUsername='admin',
        MasterUserPassword='password',
        AllocatedStorage=20,
        VpcSecurityGroupIds=[],
        DBSubnetGroupName='',
        PubliclyAccessible=False
    )
    db_instance_id = response['DBInstance']['DBInstanceIdentifier']
    print(f"MySQL RDS instance created: {db_instance_id}")
    return db_instance_id

# Function to create Redis instance
def create_redis_instance():
    response = redis_client.create_cache_cluster(
        CacheClusterId='laravel-redis',
        Engine='redis',
        CacheNodeType='cache.t2.micro',
        NumCacheNodes=1,
        SubnetGroupName='',
        VpcSecurityGroupIds=[]
    )
    redis_cluster_id = response['CacheCluster']['CacheClusterId']
    print(f"Redis instance created: {redis_cluster_id}")
    return redis_cluster_id

# Main function to create the complete architecture
def setup_laravel_system():
    # Step 1: Create VPC
    vpc_id, public_subnet_id, private_subnet_id = create_vpc()
   
    # Step 2: Create Security Groups
    security_group_id = create_security_group(vpc_id, 'laravel-security-group', 'Security group for Laravel app')
   
    # Step 3: Create EC2 instances for Load Balancer and Laravel App
    load_balancer_instance_id = create_ec2_instances(public_subnet_id, 't2.micro', 'ami-xxxxxxxx', 'your-key', security_group_id)
    laravel_app_instance_id = create_ec2_instances(private_subnet_id, 't2.micro', 'ami-xxxxxxxx', 'your-key', security_group_id)
   
    # Step 4: Create Load Balancer
    lb_arn = create_load_balancer(vpc_id, public_subnet_id)
   
    # Step 5: Create RDS MySQL instance
    db_instance_id = create_rds_instance()
   
    # Step 6: Create Redis instance
    redis_instance_id = create_redis_instance()

    print("Laravel system architecture setup is complete.")

# Run the setup
if __name__ == '__main__':
    setup_laravel_system()

Key Components in the Script

  1. VPC Setup: Creates a VPC, subnets, and an internet gateway.
  2. Security Groups: Creates a security group for EC2 instances.
  3. EC2 Instances: Creates EC2 instances for the Load Balancer and Laravel application.
  4. Load Balancer: Creates an Application Load Balancer (ALB).
  5. MySQL: Creates an RDS MySQL instance for the database.
  6. Redis: Creates an ElastiCache Redis instance.

Full Python Code to Delete Resources

python
import boto3

# Initialize boto3 clients for EC2, VPC, and other AWS services
ec2_client = boto3.client('ec2')
vpc_client = boto3.client('ec2')
elb_client = boto3.client('elbv2')
rds_client = boto3.client('rds')
redis_client = boto3.client('elasticache')

# Function to delete EC2 instances
def delete_ec2_instances(instance_ids):
    if instance_ids:
        ec2_client.terminate_instances(InstanceIds=instance_ids)
        print(f"Terminating EC2 instances: {instance_ids}")

# Function to delete Load Balancer
def delete_load_balancer(lb_arn):
    if lb_arn:
        elb_client.delete_load_balancer(
            LoadBalancerArn=lb_arn
        )
        print(f"Deleted Load Balancer: {lb_arn}")

# Function to delete RDS MySQL instance
def delete_rds_instance(db_instance_id):
    if db_instance_id:
        rds_client.delete_db_instance(
            DBInstanceIdentifier=db_instance_id,
            SkipFinalSnapshot=True
        )
        print(f"Deleted RDS MySQL instance: {db_instance_id}")

# Function to delete Redis cache cluster
def delete_redis_instance(redis_cluster_id):
    if redis_cluster_id:
        redis_client.delete_cache_cluster(
            CacheClusterId=redis_cluster_id
        )
        print(f"Deleted Redis instance: {redis_cluster_id}")

# Function to delete security group
def delete_security_group(security_group_id):
    if security_group_id:
        ec2_client.delete_security_group(
            GroupId=security_group_id
        )
        print(f"Deleted security group: {security_group_id}")

# Function to delete VPC
def delete_vpc(vpc_id):
    if vpc_id:
        # Detach and delete Internet Gateway (if exists)
        igws = vpc_client.describe_internet_gateways(Filters=[{'Name': 'attachment.vpc-id', 'Values': [vpc_id]}])
        for igw in igws['InternetGateways']:
            igw_id = igw['InternetGatewayId']
            vpc_client.detach_internet_gateway(
                InternetGatewayId=igw_id,
                VpcId=vpc_id
            )
            vpc_client.delete_internet_gateway(
                InternetGatewayId=igw_id
            )
            print(f"Deleted Internet Gateway: {igw_id}")
       
        # Delete subnets
        subnets = vpc_client.describe_subnets(Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
        for subnet in subnets['Subnets']:
            subnet_id = subnet['SubnetId']
            vpc_client.delete_subnet(SubnetId=subnet_id)
            print(f"Deleted Subnet: {subnet_id}")
       
        # Finally, delete the VPC
        vpc_client.delete_vpc(VpcId=vpc_id)
        print(f"Deleted VPC: {vpc_id}")

# Main function to delete all resources
def delete_all_resources():
    # Step 1: Delete EC2 instances (for Load Balancer and Laravel App)
    delete_ec2_instances([ 'i-xxxxxxxxxxxxxxxx', 'i-yyyyyyyyyyyyyyyy'])  # Replace with your instance IDs

    # Step 2: Delete Load Balancer
    delete_load_balancer('arn:aws:elasticloadbalancing:region:account-id:loadbalancer/app/your-load-balancer/xxxxxxxxxxxxxxx')  # Replace with your Load Balancer ARN

    # Step 3: Delete RDS MySQL instance
    delete_rds_instance('laravel-db')  # Replace with your RDS instance ID

    # Step 4: Delete Redis instance
    delete_redis_instance('laravel-redis')  # Replace with your Redis cluster ID

    # Step 5: Delete Security Group
    delete_security_group('sg-xxxxxxxx')  # Replace with your security group ID

    # Step 6: Delete VPC
    delete_vpc('vpc-xxxxxxxx')  # Replace with your VPC ID

    print("All resources have been deleted.")

# Run the cleanup process
if __name__ == '__main__':
    delete_all_resources()

Key Functions in the Code

  1. Delete EC2 Instances: Terminates all the EC2 instances (both Load Balancer and Laravel app instances).
  2. Delete Load Balancer: Deletes the Application Load Balancer (ALB) using its ARN.
  3. Delete RDS MySQL Instance: Deletes the MySQL RDS instance.
  4. Delete Redis Instance: Deletes the Redis ElastiCache cluster.
  5. Delete Security Group: Deletes the security group associated with the EC2 instances.
  6. Delete VPC: Deletes the VPC and all associated resources like subnets and Internet Gateway.

Thank you.

Publish npm package

  Để publish   pav-kit  lên NPM, bạn hãy làm theo các bước dưới đây. Tôi đã tạo thêm file  index.js  để đảm bảo gói tin hợp lệ. Bước 1: Tạo ...