mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: aws-ec2
|
||||
description: Manage EC2 instances, AMIs, and auto-scaling groups. Configure security groups, key pairs, and instance types. Use when deploying compute resources on AWS.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS EC2
|
||||
|
||||
Deploy and manage Amazon EC2 compute instances.
|
||||
|
||||
## Launch Instance
|
||||
|
||||
```bash
|
||||
aws ec2 run-instances \
|
||||
--image-id ami-0abcdef1234567890 \
|
||||
--instance-type t3.micro \
|
||||
--key-name my-key \
|
||||
--security-group-ids sg-12345678 \
|
||||
--subnet-id subnet-12345678 \
|
||||
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server}]'
|
||||
```
|
||||
|
||||
## Auto Scaling
|
||||
|
||||
```bash
|
||||
# Create launch template
|
||||
aws ec2 create-launch-template \
|
||||
--launch-template-name web-template \
|
||||
--version-description v1 \
|
||||
--launch-template-data '{
|
||||
"ImageId": "ami-xxx",
|
||||
"InstanceType": "t3.micro"
|
||||
}'
|
||||
|
||||
# Create ASG
|
||||
aws autoscaling create-auto-scaling-group \
|
||||
--auto-scaling-group-name web-asg \
|
||||
--launch-template LaunchTemplateName=web-template \
|
||||
--min-size 2 --max-size 10 --desired-capacity 2 \
|
||||
--vpc-zone-identifier "subnet-xxx,subnet-yyy"
|
||||
```
|
||||
|
||||
## User Data
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
yum update -y
|
||||
yum install -y httpd
|
||||
systemctl start httpd
|
||||
systemctl enable httpd
|
||||
```
|
||||
|
||||
## Instance Management
|
||||
|
||||
```bash
|
||||
# List instances
|
||||
aws ec2 describe-instances --filters "Name=tag:Name,Values=web*"
|
||||
|
||||
# Stop/Start
|
||||
aws ec2 stop-instances --instance-ids i-xxx
|
||||
aws ec2 start-instances --instance-ids i-xxx
|
||||
|
||||
# Create AMI
|
||||
aws ec2 create-image --instance-id i-xxx --name "my-ami"
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use launch templates
|
||||
- Implement auto-scaling
|
||||
- Use spot instances for cost savings
|
||||
- Regular AMI updates
|
||||
- Instance metadata service v2
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - IaC deployment
|
||||
- [aws-vpc](../aws-vpc/) - Networking
|
||||
@@ -0,0 +1,98 @@
|
||||
# EC2 Operations Reference
|
||||
|
||||
## Instance Management
|
||||
|
||||
```bash
|
||||
# Launch instance
|
||||
aws ec2 run-instances \
|
||||
--image-id ami-12345678 \
|
||||
--instance-type t3.micro \
|
||||
--key-name mykey \
|
||||
--security-group-ids sg-12345678 \
|
||||
--subnet-id subnet-12345678
|
||||
|
||||
# Start/Stop/Terminate
|
||||
aws ec2 start-instances --instance-ids i-12345678
|
||||
aws ec2 stop-instances --instance-ids i-12345678
|
||||
aws ec2 terminate-instances --instance-ids i-12345678
|
||||
|
||||
# Describe instances
|
||||
aws ec2 describe-instances \
|
||||
--filters "Name=tag:Environment,Values=prod"
|
||||
```
|
||||
|
||||
## AMI Management
|
||||
|
||||
```bash
|
||||
# Create AMI from instance
|
||||
aws ec2 create-image \
|
||||
--instance-id i-12345678 \
|
||||
--name "MyApp-$(date +%Y%m%d)"
|
||||
|
||||
# Copy AMI to another region
|
||||
aws ec2 copy-image \
|
||||
--source-image-id ami-12345678 \
|
||||
--source-region us-east-1 \
|
||||
--region us-west-2 \
|
||||
--name "MyApp-copy"
|
||||
```
|
||||
|
||||
## Instance Types
|
||||
|
||||
| Type | vCPU | Memory | Use Case |
|
||||
|------|------|--------|----------|
|
||||
| t3.micro | 2 | 1 GB | Dev/Test |
|
||||
| t3.small | 2 | 2 GB | Light apps |
|
||||
| m5.large | 2 | 8 GB | General |
|
||||
| c5.large | 2 | 4 GB | Compute |
|
||||
| r5.large | 2 | 16 GB | Memory |
|
||||
|
||||
## User Data
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
yum update -y
|
||||
yum install -y httpd
|
||||
systemctl start httpd
|
||||
systemctl enable httpd
|
||||
echo "Hello World" > /var/www/html/index.html
|
||||
```
|
||||
|
||||
## Instance Metadata
|
||||
|
||||
```bash
|
||||
# IMDSv2
|
||||
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
||||
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
|
||||
|
||||
# Common endpoints
|
||||
/latest/meta-data/instance-id
|
||||
/latest/meta-data/local-ipv4
|
||||
/latest/meta-data/public-ipv4
|
||||
/latest/meta-data/iam/security-credentials/role-name
|
||||
```
|
||||
|
||||
## Terraform
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "app" {
|
||||
ami = data.aws_ami.amazon_linux.id
|
||||
instance_type = "t3.micro"
|
||||
|
||||
vpc_security_group_ids = [aws_security_group.app.id]
|
||||
subnet_id = aws_subnet.private.id
|
||||
|
||||
iam_instance_profile = aws_iam_instance_profile.app.name
|
||||
|
||||
user_data = base64encode(file("userdata.sh"))
|
||||
|
||||
root_block_device {
|
||||
volume_size = 20
|
||||
encrypted = true
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "app-server"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: aws-ecs-fargate
|
||||
description: Deploy containers on ECS and Fargate. Configure task definitions, services, and load balancing. Use when running containerized workloads on AWS.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS ECS & Fargate
|
||||
|
||||
Run containerized applications on Amazon ECS with Fargate.
|
||||
|
||||
## Task Definition
|
||||
|
||||
```json
|
||||
{
|
||||
"family": "myapp",
|
||||
"networkMode": "awsvpc",
|
||||
"requiresCompatibilities": ["FARGATE"],
|
||||
"cpu": "256",
|
||||
"memory": "512",
|
||||
"executionRoleArn": "arn:aws:iam::xxx:role/ecsTaskExecutionRole",
|
||||
"containerDefinitions": [{
|
||||
"name": "myapp",
|
||||
"image": "xxx.dkr.ecr.region.amazonaws.com/myapp:latest",
|
||||
"portMappings": [{
|
||||
"containerPort": 8080,
|
||||
"protocol": "tcp"
|
||||
}],
|
||||
"logConfiguration": {
|
||||
"logDriver": "awslogs",
|
||||
"options": {
|
||||
"awslogs-group": "/ecs/myapp",
|
||||
"awslogs-region": "us-east-1",
|
||||
"awslogs-stream-prefix": "ecs"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Create Service
|
||||
|
||||
```bash
|
||||
aws ecs create-service \
|
||||
--cluster my-cluster \
|
||||
--service-name myapp \
|
||||
--task-definition myapp:1 \
|
||||
--desired-count 2 \
|
||||
--launch-type FARGATE \
|
||||
--network-configuration '{
|
||||
"awsvpcConfiguration": {
|
||||
"subnets": ["subnet-xxx"],
|
||||
"securityGroups": ["sg-xxx"],
|
||||
"assignPublicIp": "ENABLED"
|
||||
}
|
||||
}' \
|
||||
--load-balancers '[{
|
||||
"targetGroupArn": "arn:aws:elasticloadbalancing:...",
|
||||
"containerName": "myapp",
|
||||
"containerPort": 8080
|
||||
}]'
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
# Update service
|
||||
aws ecs update-service \
|
||||
--cluster my-cluster \
|
||||
--service myapp \
|
||||
--task-definition myapp:2 \
|
||||
--force-new-deployment
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use ECR for images
|
||||
- Implement service discovery
|
||||
- Configure health checks
|
||||
- Use secrets manager for secrets
|
||||
- Enable container insights
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [docker-management](../../../devops/containers/docker-management/) - Container basics
|
||||
- [container-registries](../../../devops/containers/container-registries/) - ECR
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: aws-iam
|
||||
description: Manage IAM users, roles, and policies. Implement least-privilege access and security best practices. Use when configuring AWS identity and access management.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS IAM
|
||||
|
||||
Manage identity and access in AWS.
|
||||
|
||||
## IAM Policies
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetObject",
|
||||
"s3:PutObject"
|
||||
],
|
||||
"Resource": "arn:aws:s3:::my-bucket/*"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
```bash
|
||||
# Create role with trust policy
|
||||
aws iam create-role \
|
||||
--role-name EC2AppRole \
|
||||
--assume-role-policy-document '{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "ec2.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}]
|
||||
}'
|
||||
|
||||
# Attach policy
|
||||
aws iam attach-role-policy \
|
||||
--role-name EC2AppRole \
|
||||
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
|
||||
```
|
||||
|
||||
## Service-Linked Roles
|
||||
|
||||
```bash
|
||||
# For services like ECS, RDS
|
||||
aws iam create-service-linked-role \
|
||||
--aws-service-name ecs.amazonaws.com
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
```yaml
|
||||
security_practices:
|
||||
- Use roles, not long-term credentials
|
||||
- Implement least privilege
|
||||
- Enable MFA
|
||||
- Regular access reviews
|
||||
- Use IAM Access Analyzer
|
||||
- Implement SCPs for organizations
|
||||
```
|
||||
|
||||
## Policy Conditions
|
||||
|
||||
```json
|
||||
{
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"aws:RequestedRegion": "us-east-1"
|
||||
},
|
||||
"Bool": {
|
||||
"aws:MultiFactorAuthPresent": "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Follow least privilege
|
||||
- Use IAM roles for applications
|
||||
- Enable CloudTrail for auditing
|
||||
- Regular credential rotation
|
||||
- Use permission boundaries
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - IaC deployment
|
||||
- [access-review](../../../compliance/governance/access-review/) - Access auditing
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
name: aws-lambda
|
||||
description: Build and deploy serverless functions on AWS Lambda. Configure triggers, manage permissions, and optimize performance. Use when implementing serverless applications.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS Lambda
|
||||
|
||||
Build serverless applications with AWS Lambda.
|
||||
|
||||
## Create Function
|
||||
|
||||
```bash
|
||||
# Create function
|
||||
aws lambda create-function \
|
||||
--function-name myfunction \
|
||||
--runtime python3.11 \
|
||||
--handler app.handler \
|
||||
--role arn:aws:iam::xxx:role/lambda-role \
|
||||
--zip-file fileb://function.zip
|
||||
|
||||
# Update code
|
||||
aws lambda update-function-code \
|
||||
--function-name myfunction \
|
||||
--zip-file fileb://function.zip
|
||||
```
|
||||
|
||||
## Function Code
|
||||
|
||||
```python
|
||||
# app.py
|
||||
import json
|
||||
|
||||
def handler(event, context):
|
||||
return {
|
||||
'statusCode': 200,
|
||||
'body': json.dumps({'message': 'Hello!'})
|
||||
}
|
||||
```
|
||||
|
||||
## API Gateway Integration
|
||||
|
||||
```bash
|
||||
# Create REST API
|
||||
aws apigateway create-rest-api --name myapi
|
||||
|
||||
# Add Lambda permission
|
||||
aws lambda add-permission \
|
||||
--function-name myfunction \
|
||||
--statement-id apigateway \
|
||||
--action lambda:InvokeFunction \
|
||||
--principal apigateway.amazonaws.com
|
||||
```
|
||||
|
||||
## Environment & Configuration
|
||||
|
||||
```bash
|
||||
# Set environment variables
|
||||
aws lambda update-function-configuration \
|
||||
--function-name myfunction \
|
||||
--environment "Variables={DB_HOST=xxx,API_KEY=yyy}"
|
||||
|
||||
# Set memory and timeout
|
||||
aws lambda update-function-configuration \
|
||||
--function-name myfunction \
|
||||
--memory-size 256 \
|
||||
--timeout 30
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Minimize cold starts
|
||||
- Use layers for dependencies
|
||||
- Implement proper error handling
|
||||
- Use provisioned concurrency for latency-sensitive functions
|
||||
- Monitor with CloudWatch
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - IaC deployment
|
||||
- [aws-iam](../aws-iam/) - Execution roles
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
name: aws-rds
|
||||
description: Provision and manage RDS databases. Configure backups, replication, and security. Use when deploying managed relational databases on AWS.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS RDS
|
||||
|
||||
Deploy managed relational databases with Amazon RDS.
|
||||
|
||||
## Create Database
|
||||
|
||||
```bash
|
||||
aws rds create-db-instance \
|
||||
--db-instance-identifier mydb \
|
||||
--db-instance-class db.t3.micro \
|
||||
--engine postgres \
|
||||
--engine-version 15 \
|
||||
--master-username admin \
|
||||
--master-user-password secretpassword \
|
||||
--allocated-storage 20 \
|
||||
--storage-encrypted \
|
||||
--vpc-security-group-ids sg-xxx \
|
||||
--db-subnet-group-name my-subnet-group \
|
||||
--backup-retention-period 7 \
|
||||
--multi-az
|
||||
```
|
||||
|
||||
## Parameter Groups
|
||||
|
||||
```bash
|
||||
aws rds create-db-parameter-group \
|
||||
--db-parameter-group-name custom-pg \
|
||||
--db-parameter-group-family postgres15 \
|
||||
--description "Custom PostgreSQL parameters"
|
||||
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name custom-pg \
|
||||
--parameters "ParameterName=max_connections,ParameterValue=200,ApplyMethod=pending-reboot"
|
||||
```
|
||||
|
||||
## Snapshots & Recovery
|
||||
|
||||
```bash
|
||||
# Create snapshot
|
||||
aws rds create-db-snapshot \
|
||||
--db-instance-identifier mydb \
|
||||
--db-snapshot-identifier mydb-snapshot
|
||||
|
||||
# Restore from snapshot
|
||||
aws rds restore-db-instance-from-db-snapshot \
|
||||
--db-instance-identifier mydb-restored \
|
||||
--db-snapshot-identifier mydb-snapshot
|
||||
```
|
||||
|
||||
## Read Replicas
|
||||
|
||||
```bash
|
||||
aws rds create-db-instance-read-replica \
|
||||
--db-instance-identifier mydb-replica \
|
||||
--source-db-instance-identifier mydb
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Enable Multi-AZ for production
|
||||
- Use encryption at rest
|
||||
- Implement automated backups
|
||||
- Use read replicas for read scaling
|
||||
- Store credentials in Secrets Manager
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - IaC deployment
|
||||
- [aws-secrets-manager](../../../security/secrets/aws-secrets-manager/) - Credentials
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: aws-s3
|
||||
description: Configure S3 buckets, policies, and lifecycle rules. Implement versioning, replication, and security. Use when managing object storage on AWS.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS S3
|
||||
|
||||
Manage object storage with Amazon S3.
|
||||
|
||||
## Create Bucket
|
||||
|
||||
```bash
|
||||
aws s3api create-bucket \
|
||||
--bucket my-bucket \
|
||||
--region us-east-1
|
||||
|
||||
# Enable versioning
|
||||
aws s3api put-bucket-versioning \
|
||||
--bucket my-bucket \
|
||||
--versioning-configuration Status=Enabled
|
||||
|
||||
# Block public access
|
||||
aws s3api put-public-access-block \
|
||||
--bucket my-bucket \
|
||||
--public-access-block-configuration '{
|
||||
"BlockPublicAcls": true,
|
||||
"IgnorePublicAcls": true,
|
||||
"BlockPublicPolicy": true,
|
||||
"RestrictPublicBuckets": true
|
||||
}'
|
||||
```
|
||||
|
||||
## Bucket Policy
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Sid": "EnforceHTTPS",
|
||||
"Effect": "Deny",
|
||||
"Principal": "*",
|
||||
"Action": "s3:*",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::my-bucket",
|
||||
"arn:aws:s3:::my-bucket/*"
|
||||
],
|
||||
"Condition": {
|
||||
"Bool": {"aws:SecureTransport": "false"}
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Lifecycle Rules
|
||||
|
||||
```bash
|
||||
aws s3api put-bucket-lifecycle-configuration \
|
||||
--bucket my-bucket \
|
||||
--lifecycle-configuration '{
|
||||
"Rules": [{
|
||||
"ID": "Archive old objects",
|
||||
"Status": "Enabled",
|
||||
"Filter": {"Prefix": "logs/"},
|
||||
"Transitions": [{
|
||||
"Days": 30,
|
||||
"StorageClass": "GLACIER"
|
||||
}],
|
||||
"Expiration": {"Days": 365}
|
||||
}]
|
||||
}'
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Enable versioning
|
||||
- Block public access
|
||||
- Use encryption (SSE-S3 or SSE-KMS)
|
||||
- Implement lifecycle policies
|
||||
- Enable access logging
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - IaC deployment
|
||||
- [aws-iam](../aws-iam/) - Access policies
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
name: aws-vpc
|
||||
description: Design and implement VPCs and networking. Configure subnets, route tables, and security groups. Use when setting up AWS network infrastructure.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# AWS VPC
|
||||
|
||||
Design and manage Virtual Private Cloud networking.
|
||||
|
||||
## Create VPC
|
||||
|
||||
```bash
|
||||
# Create VPC
|
||||
aws ec2 create-vpc --cidr-block 10.0.0.0/16
|
||||
|
||||
# Create subnets
|
||||
aws ec2 create-subnet \
|
||||
--vpc-id vpc-xxx \
|
||||
--cidr-block 10.0.1.0/24 \
|
||||
--availability-zone us-east-1a
|
||||
|
||||
# Create internet gateway
|
||||
aws ec2 create-internet-gateway
|
||||
aws ec2 attach-internet-gateway --vpc-id vpc-xxx --internet-gateway-id igw-xxx
|
||||
```
|
||||
|
||||
## Network Architecture
|
||||
|
||||
```
|
||||
VPC (10.0.0.0/16)
|
||||
├── Public Subnets
|
||||
│ ├── 10.0.1.0/24 (us-east-1a)
|
||||
│ └── 10.0.2.0/24 (us-east-1b)
|
||||
├── Private Subnets
|
||||
│ ├── 10.0.11.0/24 (us-east-1a)
|
||||
│ └── 10.0.12.0/24 (us-east-1b)
|
||||
├── Internet Gateway
|
||||
├── NAT Gateway (in public subnet)
|
||||
└── Route Tables
|
||||
```
|
||||
|
||||
## Security Groups
|
||||
|
||||
```bash
|
||||
aws ec2 create-security-group \
|
||||
--group-name web-sg \
|
||||
--description "Web server security group" \
|
||||
--vpc-id vpc-xxx
|
||||
|
||||
aws ec2 authorize-security-group-ingress \
|
||||
--group-id sg-xxx \
|
||||
--protocol tcp \
|
||||
--port 443 \
|
||||
--cidr 0.0.0.0/0
|
||||
```
|
||||
|
||||
## NAT Gateway
|
||||
|
||||
```bash
|
||||
# Allocate EIP
|
||||
aws ec2 allocate-address --domain vpc
|
||||
|
||||
# Create NAT Gateway
|
||||
aws ec2 create-nat-gateway \
|
||||
--subnet-id subnet-public \
|
||||
--allocation-id eipalloc-xxx
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use multiple AZs
|
||||
- Separate public/private subnets
|
||||
- Implement VPC Flow Logs
|
||||
- Use security groups effectively
|
||||
- Plan CIDR ranges carefully
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - IaC deployment
|
||||
- [firewall-config](../../../security/network/firewall-config/) - Security
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: cloudformation
|
||||
description: Deploy AWS resources with CloudFormation templates. Create stacks, use nested stacks, and implement drift detection. Use when deploying AWS-native IaC.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# CloudFormation
|
||||
|
||||
Deploy AWS infrastructure with native CloudFormation templates.
|
||||
|
||||
## Template Structure
|
||||
|
||||
```yaml
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: Web application stack
|
||||
|
||||
Parameters:
|
||||
Environment:
|
||||
Type: String
|
||||
AllowedValues: [dev, staging, prod]
|
||||
|
||||
Resources:
|
||||
WebServer:
|
||||
Type: AWS::EC2::Instance
|
||||
Properties:
|
||||
ImageId: !Ref AMI
|
||||
InstanceType: t3.micro
|
||||
Tags:
|
||||
- Key: Name
|
||||
Value: !Sub '${Environment}-web'
|
||||
|
||||
Outputs:
|
||||
InstanceId:
|
||||
Value: !Ref WebServer
|
||||
Export:
|
||||
Name: !Sub '${Environment}-WebServerId'
|
||||
```
|
||||
|
||||
## Stack Operations
|
||||
|
||||
```bash
|
||||
# Create stack
|
||||
aws cloudformation create-stack \
|
||||
--stack-name myapp \
|
||||
--template-body file://template.yaml \
|
||||
--parameters ParameterKey=Environment,ParameterValue=prod
|
||||
|
||||
# Update stack
|
||||
aws cloudformation update-stack \
|
||||
--stack-name myapp \
|
||||
--template-body file://template.yaml
|
||||
|
||||
# Delete stack
|
||||
aws cloudformation delete-stack --stack-name myapp
|
||||
|
||||
# Detect drift
|
||||
aws cloudformation detect-stack-drift --stack-name myapp
|
||||
```
|
||||
|
||||
## Intrinsic Functions
|
||||
|
||||
```yaml
|
||||
# Reference
|
||||
!Ref MyResource
|
||||
|
||||
# Get attribute
|
||||
!GetAtt MyResource.Arn
|
||||
|
||||
# Substitute
|
||||
!Sub 'arn:aws:s3:::${BucketName}/*'
|
||||
|
||||
# Conditional
|
||||
!If [CreateProdResources, 't3.large', 't3.micro']
|
||||
|
||||
# Join
|
||||
!Join ['-', [!Ref Environment, 'app', 'bucket']]
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use change sets before updates
|
||||
- Implement stack policies
|
||||
- Use nested stacks for modularity
|
||||
- Enable termination protection
|
||||
- Use cfn-lint for validation
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../terraform-aws/) - Alternative IaC
|
||||
- [aws-iam](../aws-iam/) - IAM resources
|
||||
@@ -0,0 +1,123 @@
|
||||
# CloudFormation Syntax Reference
|
||||
|
||||
## Template Structure
|
||||
|
||||
```yaml
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: My CloudFormation Template
|
||||
|
||||
Parameters:
|
||||
Environment:
|
||||
Type: String
|
||||
AllowedValues: [dev, staging, prod]
|
||||
|
||||
Mappings:
|
||||
RegionMap:
|
||||
us-east-1:
|
||||
AMI: ami-12345678
|
||||
|
||||
Conditions:
|
||||
IsProd: !Equals [!Ref Environment, prod]
|
||||
|
||||
Resources:
|
||||
MyBucket:
|
||||
Type: AWS::S3::Bucket
|
||||
Properties:
|
||||
BucketName: !Sub '${AWS::StackName}-bucket'
|
||||
|
||||
Outputs:
|
||||
BucketName:
|
||||
Value: !Ref MyBucket
|
||||
Export:
|
||||
Name: !Sub '${AWS::StackName}-bucket'
|
||||
```
|
||||
|
||||
## Intrinsic Functions
|
||||
|
||||
```yaml
|
||||
# Reference
|
||||
!Ref MyResource
|
||||
|
||||
# GetAtt
|
||||
!GetAtt MyResource.Arn
|
||||
|
||||
# Sub (string substitution)
|
||||
!Sub '${AWS::StackName}-resource'
|
||||
!Sub
|
||||
- 'arn:aws:s3:::${Bucket}/*'
|
||||
- Bucket: !Ref MyBucket
|
||||
|
||||
# Join
|
||||
!Join ['-', [!Ref Environment, app]]
|
||||
|
||||
# Select
|
||||
!Select [0, !GetAZs '']
|
||||
|
||||
# Split
|
||||
!Split [',', 'a,b,c']
|
||||
|
||||
# If
|
||||
!If [IsProd, 3, 1]
|
||||
|
||||
# ImportValue
|
||||
!ImportValue ExportedValue
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Cross-Stack References
|
||||
```yaml
|
||||
# Stack A - Export
|
||||
Outputs:
|
||||
VpcId:
|
||||
Value: !Ref VPC
|
||||
Export:
|
||||
Name: SharedVPC
|
||||
|
||||
# Stack B - Import
|
||||
Resources:
|
||||
Subnet:
|
||||
Type: AWS::EC2::Subnet
|
||||
Properties:
|
||||
VpcId: !ImportValue SharedVPC
|
||||
```
|
||||
|
||||
### Nested Stacks
|
||||
```yaml
|
||||
Resources:
|
||||
VPCStack:
|
||||
Type: AWS::CloudFormation::Stack
|
||||
Properties:
|
||||
TemplateURL: https://s3.amazonaws.com/bucket/vpc.yaml
|
||||
Parameters:
|
||||
Environment: !Ref Environment
|
||||
```
|
||||
|
||||
### DependsOn
|
||||
```yaml
|
||||
Resources:
|
||||
MyInstance:
|
||||
Type: AWS::EC2::Instance
|
||||
DependsOn: MySecurityGroup
|
||||
```
|
||||
|
||||
## CLI Commands
|
||||
|
||||
```bash
|
||||
# Create stack
|
||||
aws cloudformation create-stack \
|
||||
--stack-name mystack \
|
||||
--template-body file://template.yaml \
|
||||
--parameters ParameterKey=Environment,ParameterValue=prod
|
||||
|
||||
# Update stack
|
||||
aws cloudformation update-stack \
|
||||
--stack-name mystack \
|
||||
--template-body file://template.yaml
|
||||
|
||||
# Delete stack
|
||||
aws cloudformation delete-stack --stack-name mystack
|
||||
|
||||
# Validate template
|
||||
aws cloudformation validate-template --template-body file://template.yaml
|
||||
```
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
name: terraform-aws
|
||||
description: Provision AWS infrastructure with Terraform. Create modules, manage state, and implement IaC best practices. Use when deploying AWS resources declaratively.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# Terraform AWS
|
||||
|
||||
Provision and manage AWS infrastructure with Terraform.
|
||||
|
||||
## Provider Configuration
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
}
|
||||
|
||||
backend "s3" {
|
||||
bucket = "terraform-state"
|
||||
key = "prod/terraform.tfstate"
|
||||
region = "us-east-1"
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = var.region
|
||||
|
||||
default_tags {
|
||||
tags = {
|
||||
Environment = var.environment
|
||||
ManagedBy = "terraform"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example Resources
|
||||
|
||||
```hcl
|
||||
resource "aws_vpc" "main" {
|
||||
cidr_block = "10.0.0.0/16"
|
||||
enable_dns_hostnames = true
|
||||
|
||||
tags = { Name = "main-vpc" }
|
||||
}
|
||||
|
||||
resource "aws_instance" "web" {
|
||||
ami = data.aws_ami.amazon_linux.id
|
||||
instance_type = "t3.micro"
|
||||
subnet_id = aws_subnet.public.id
|
||||
|
||||
tags = { Name = "web-server" }
|
||||
}
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
```hcl
|
||||
module "vpc" {
|
||||
source = "terraform-aws-modules/vpc/aws"
|
||||
|
||||
name = "my-vpc"
|
||||
cidr = "10.0.0.0/16"
|
||||
|
||||
azs = ["us-east-1a", "us-east-1b"]
|
||||
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
|
||||
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
|
||||
|
||||
enable_nat_gateway = true
|
||||
}
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform plan -out=plan.tfplan
|
||||
terraform apply plan.tfplan
|
||||
terraform destroy
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use remote state with locking
|
||||
- Implement module structure
|
||||
- Use workspaces or separate states per environment
|
||||
- Pin provider versions
|
||||
- Use data sources for AMIs
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [aws-vpc](../aws-vpc/) - VPC networking
|
||||
- [aws-iam](../aws-iam/) - IAM policies
|
||||
@@ -0,0 +1,152 @@
|
||||
# AWS VPC Module Template
|
||||
# Production-ready VPC with public and private subnets
|
||||
|
||||
variable "vpc_cidr" {
|
||||
description = "CIDR block for VPC"
|
||||
type = string
|
||||
default = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
variable "availability_zones" {
|
||||
description = "Availability zones"
|
||||
type = list(string)
|
||||
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
|
||||
}
|
||||
|
||||
variable "enable_nat_gateway" {
|
||||
description = "Enable NAT Gateway for private subnets"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
locals {
|
||||
public_subnets = [for i, az in var.availability_zones : cidrsubnet(var.vpc_cidr, 8, i)]
|
||||
private_subnets = [for i, az in var.availability_zones : cidrsubnet(var.vpc_cidr, 8, i + 10)]
|
||||
}
|
||||
|
||||
# VPC
|
||||
resource "aws_vpc" "main" {
|
||||
cidr_block = var.vpc_cidr
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-vpc"
|
||||
}
|
||||
}
|
||||
|
||||
# Internet Gateway
|
||||
resource "aws_internet_gateway" "main" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
# Public Subnets
|
||||
resource "aws_subnet" "public" {
|
||||
count = length(var.availability_zones)
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = local.public_subnets[count.index]
|
||||
availability_zone = var.availability_zones[count.index]
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-public-${var.availability_zones[count.index]}"
|
||||
"kubernetes.io/role/elb" = "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Private Subnets
|
||||
resource "aws_subnet" "private" {
|
||||
count = length(var.availability_zones)
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = local.private_subnets[count.index]
|
||||
availability_zone = var.availability_zones[count.index]
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-private-${var.availability_zones[count.index]}"
|
||||
"kubernetes.io/role/internal-elb" = "1"
|
||||
}
|
||||
}
|
||||
|
||||
# Elastic IP for NAT Gateway
|
||||
resource "aws_eip" "nat" {
|
||||
count = var.enable_nat_gateway ? 1 : 0
|
||||
domain = "vpc"
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-nat-eip"
|
||||
}
|
||||
}
|
||||
|
||||
# NAT Gateway
|
||||
resource "aws_nat_gateway" "main" {
|
||||
count = var.enable_nat_gateway ? 1 : 0
|
||||
allocation_id = aws_eip.nat[0].id
|
||||
subnet_id = aws_subnet.public[0].id
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-nat"
|
||||
}
|
||||
|
||||
depends_on = [aws_internet_gateway.main]
|
||||
}
|
||||
|
||||
# Public Route Table
|
||||
resource "aws_route_table" "public" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.main.id
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-public-rt"
|
||||
}
|
||||
}
|
||||
|
||||
# Private Route Table
|
||||
resource "aws_route_table" "private" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
dynamic "route" {
|
||||
for_each = var.enable_nat_gateway ? [1] : []
|
||||
content {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.main[0].id
|
||||
}
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-private-rt"
|
||||
}
|
||||
}
|
||||
|
||||
# Route Table Associations
|
||||
resource "aws_route_table_association" "public" {
|
||||
count = length(var.availability_zones)
|
||||
subnet_id = aws_subnet.public[count.index].id
|
||||
route_table_id = aws_route_table.public.id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private" {
|
||||
count = length(var.availability_zones)
|
||||
subnet_id = aws_subnet.private[count.index].id
|
||||
route_table_id = aws_route_table.private.id
|
||||
}
|
||||
|
||||
# Outputs
|
||||
output "vpc_id" {
|
||||
value = aws_vpc.main.id
|
||||
}
|
||||
|
||||
output "public_subnet_ids" {
|
||||
value = aws_subnet.public[*].id
|
||||
}
|
||||
|
||||
output "private_subnet_ids" {
|
||||
value = aws_subnet.private[*].id
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
# Terraform AWS Best Practices
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
project/
|
||||
├── main.tf # Main configuration
|
||||
├── variables.tf # Input variables
|
||||
├── outputs.tf # Output values
|
||||
├── locals.tf # Local values
|
||||
├── data.tf # Data sources
|
||||
├── versions.tf # Provider versions
|
||||
├── terraform.tfvars # Variable values (git-ignored)
|
||||
├── modules/ # Local modules
|
||||
│ └── vpc/
|
||||
│ ├── main.tf
|
||||
│ ├── variables.tf
|
||||
│ └── outputs.tf
|
||||
└── environments/ # Environment configs
|
||||
├── dev/
|
||||
├── staging/
|
||||
└── prod/
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
### Remote State with S3
|
||||
```hcl
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "company-terraform-state"
|
||||
key = "project/env/terraform.tfstate"
|
||||
region = "us-east-1"
|
||||
encrypt = true
|
||||
dynamodb_table = "terraform-locks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### State Locking
|
||||
```hcl
|
||||
resource "aws_dynamodb_table" "terraform_locks" {
|
||||
name = "terraform-locks"
|
||||
billing_mode = "PAY_PER_REQUEST"
|
||||
hash_key = "LockID"
|
||||
|
||||
attribute {
|
||||
name = "LockID"
|
||||
type = "S"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Use IAM Roles, Not Credentials
|
||||
```hcl
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
# No access_key or secret_key - use IAM role or env vars
|
||||
}
|
||||
```
|
||||
|
||||
### Enable Encryption Everywhere
|
||||
```hcl
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
|
||||
bucket = aws_s3_bucket.example.id
|
||||
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = "aws:kms"
|
||||
kms_master_key_id = aws_kms_key.example.arn
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use Sensitive Variables
|
||||
```hcl
|
||||
variable "database_password" {
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
```
|
||||
|
||||
## Tagging Strategy
|
||||
|
||||
```hcl
|
||||
locals {
|
||||
common_tags = {
|
||||
Project = var.project_name
|
||||
Environment = var.environment
|
||||
ManagedBy = "terraform"
|
||||
Owner = var.team
|
||||
CostCenter = var.cost_center
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_instance" "example" {
|
||||
# ... configuration ...
|
||||
|
||||
tags = merge(local.common_tags, {
|
||||
Name = "example-instance"
|
||||
Role = "web"
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Module Best Practices
|
||||
|
||||
### Version Pinning
|
||||
```hcl
|
||||
module "vpc" {
|
||||
source = "terraform-aws-modules/vpc/aws"
|
||||
version = "5.0.0" # Pin specific version
|
||||
|
||||
# ... configuration ...
|
||||
}
|
||||
```
|
||||
|
||||
### Variable Validation
|
||||
```hcl
|
||||
variable "environment" {
|
||||
type = string
|
||||
description = "Environment name"
|
||||
|
||||
validation {
|
||||
condition = contains(["dev", "staging", "prod"], var.environment)
|
||||
error_message = "Environment must be dev, staging, or prod."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### Plan Before Apply
|
||||
```bash
|
||||
terraform plan -out=tfplan
|
||||
terraform apply tfplan
|
||||
```
|
||||
|
||||
### Use Workspaces or Directories for Environments
|
||||
```bash
|
||||
# Workspaces
|
||||
terraform workspace new prod
|
||||
terraform workspace select prod
|
||||
|
||||
# Or separate directories (recommended)
|
||||
cd environments/prod
|
||||
terraform apply
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Data Sources for Existing Resources
|
||||
```hcl
|
||||
data "aws_vpc" "existing" {
|
||||
filter {
|
||||
name = "tag:Name"
|
||||
values = ["main-vpc"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "new" {
|
||||
vpc_id = data.aws_vpc.existing.id
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic Blocks
|
||||
```hcl
|
||||
resource "aws_security_group" "example" {
|
||||
# ...
|
||||
|
||||
dynamic "ingress" {
|
||||
for_each = var.ingress_rules
|
||||
content {
|
||||
from_port = ingress.value.from_port
|
||||
to_port = ingress.value.to_port
|
||||
protocol = ingress.value.protocol
|
||||
cidr_blocks = ingress.value.cidr_blocks
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
# Terraform AWS Project Initialization Script
|
||||
# Usage: ./tf-init.sh <project-name> [region]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_NAME="${1:-}"
|
||||
REGION="${2:-us-east-1}"
|
||||
|
||||
if [ -z "$PROJECT_NAME" ]; then
|
||||
echo "Usage: $0 <project-name> [region]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "========================================="
|
||||
echo "Terraform AWS Project Setup"
|
||||
echo "Project: $PROJECT_NAME"
|
||||
echo "Region: $REGION"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
mkdir -p "$PROJECT_NAME"
|
||||
cd "$PROJECT_NAME"
|
||||
|
||||
# Create main.tf
|
||||
cat > main.tf << EOF
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
}
|
||||
|
||||
# Uncomment for remote state
|
||||
# backend "s3" {
|
||||
# bucket = "${PROJECT_NAME}-tfstate"
|
||||
# key = "terraform.tfstate"
|
||||
# region = "${REGION}"
|
||||
# encrypt = true
|
||||
# dynamodb_table = "${PROJECT_NAME}-tflock"
|
||||
# }
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = var.region
|
||||
|
||||
default_tags {
|
||||
tags = {
|
||||
Project = var.project_name
|
||||
Environment = var.environment
|
||||
ManagedBy = "terraform"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create variables.tf
|
||||
cat > variables.tf << EOF
|
||||
variable "project_name" {
|
||||
description = "Project name for tagging"
|
||||
type = string
|
||||
default = "${PROJECT_NAME}"
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
description = "Environment (dev, staging, prod)"
|
||||
type = string
|
||||
default = "dev"
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "AWS region"
|
||||
type = string
|
||||
default = "${REGION}"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create outputs.tf
|
||||
cat > outputs.tf << EOF
|
||||
output "region" {
|
||||
description = "AWS region"
|
||||
value = var.region
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create terraform.tfvars
|
||||
cat > terraform.tfvars << EOF
|
||||
project_name = "${PROJECT_NAME}"
|
||||
environment = "dev"
|
||||
region = "${REGION}"
|
||||
EOF
|
||||
|
||||
# Create .gitignore
|
||||
cat > .gitignore << EOF
|
||||
# Terraform
|
||||
.terraform/
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
*.tfvars.json
|
||||
crash.log
|
||||
*.tfplan
|
||||
|
||||
# Keep tfvars template
|
||||
!terraform.tfvars.example
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
.vscode/
|
||||
EOF
|
||||
|
||||
# Initialize Terraform
|
||||
echo ""
|
||||
echo "Initializing Terraform..."
|
||||
terraform init
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "Project created successfully!"
|
||||
echo ""
|
||||
echo "Files created:"
|
||||
ls -la
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. cd $PROJECT_NAME"
|
||||
echo " 2. Edit terraform.tfvars"
|
||||
echo " 3. Add resources to main.tf"
|
||||
echo " 4. terraform plan"
|
||||
echo " 5. terraform apply"
|
||||
echo "========================================="
|
||||
Reference in New Issue
Block a user