A fully automated, production-grade static website for RD Service
Pros, a home repair & appliance service company in Navarre,
Florida.
The project demonstrates end-to-end DevOps engineering, including
infrastructure-as-code, CDN-level optimization, secure deployments, and
real incident resolution.
Built using AWS S3 + CloudFront, with DNS routed through Route53, and deployed via GitHub Actions OIDC (no access keys).
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | HTML5, Bootstrap 5, JS | Responsive, production-ready static site |
| Hosting | S3 (private) | Secure static content origin |
| CDN | CloudFront (OAC) | HTTPS delivery, edge caching, compression |
| DNS | Route53 | Apex + www A-aliases, ACM DNS validation |
| Security | IAM Roles + OIDC | GitHub Actions assumes an IAM role β no long-lived AWS keys used |
| IaC | Terraform | Full infrastructure provisioning and configuration |
| CI/CD | GitHub Actions | Automated deploy + CloudFront invalidation |
- Multi-account domain setup (registrar in A β hosted zone + CloudFront in B)\
- Private S3 bucket --- no public ACLs, access only via CloudFront OAC\
- ACM certificate in
us-east-1for CloudFront, DNS-validated\ - Smart caching strategy:
- HTML = 60 seconds\
- Assets = 1 year\
- Zero access keys --- GitHub Actions assumes IAM role via OIDC\
- Automatic CloudFront invalidations on deploy\
- Fully reproducible infrastructure using Terraform\
- Custom 404 page + forced HTTPS\
- Clean resource naming & consistent tagging
This static hosting setup is tuned for fast global delivery and low-cost performance:
- HTML β 60s TTL
- Static assets β 1 year TTL
- Automatic CloudFront invalidations per deploy
- Brotli/Gzip compression
- HTTP/2 support
- Optimized static assets
- Apex + www served entirely from CloudFront\
- ~400 global edge locations
- Minimal redirects (HTTP β HTTPS only, no extra redirect chains)
- Proper domain aliasing
- PriceClass_100\
- Zero compute\
- High cache-hit ratio
graph TD
A[User Browser π] -->|HTTPS Request| B[CloudFront CDN]
B -->|Fetches Content| C[S3 Static Website Bucket]
B -->|DNS Resolution| D[Route53 Hosted Zone]
E[GitHub Actions βοΈ] -->|Deploy via OIDC| C
subgraph AWS Cloud
C -->|Content| B
D --> B
end
subgraph CI/CD
F[Terraform IaC] --> C
F --> B
end
rdservicepros-site/
βββ docs/ # Documentation & screenshots
βββ infra/ # Terraform IaC (S3, CloudFront, Route53, OIDC)
βββ site/ # Static website source (HTML + assets)
βββ .github/ # CI/CD workflows
βββ README.md # Project overview
βββ LICENSE # MIT license + branding notice
βββ .gitignore # Repo hygiene rules
βββ .tfsec.yml # Security scanning configuration
Full detailed structure: see docs/architecture.md
cd infra/terraform
terraform init
terraform applyaws s3 sync site s3://$(terraform output -raw bucket_name) --delete
aws cloudfront create-invalidation \
--distribution-id $(terraform output -raw cloudfront_distribution_id) \
--paths "/*"This project uses a full IaC validation pipeline to ensure correctness, security, and consistency:
| Tool | Purpose |
|---|---|
| terraform validate / fmt | Syntax checks and formatting |
| TFLint | Provider-aware linting (AWS rules, deprecated args, typos) |
| tfsec | Security scanning with selected rules excluded |
| Checkov | Deep IaC policy evaluation (all current checks passed) |
| GitHub Actions | Optional CI integration for automated scanning |
Certain tfsec / checkov rules were intentionally ignored because:
- They increase AWS cost (WAF, S3 versioning, CloudFront logging, KMS CMKs)
- They are unnecessary for a static brochure-style site (no backend, no data retention, no sensitive compute)
- They do not improve real-world security for this architecture
Example: Enforcing KMS CMK encryption on a public static website bucket has no practical benefit, but costs money. - Some rules are false positives due to CloudFront provider quirks (e.g., TLS policy mismatches)
This keeps the project:
- Fully secure
- Minimalistic
- Free-tier friendly
- Aligned with the real threat model (no user data, no API surface, no dynamic workloads)
terraform fmt -recursive
terraform validate
tflint
tfsec .
checkov -d infra/terraformwww.rdservicepros.comworked\rdservicepros.comfailed globally
Registrar NS did not match newly created Route53 hosted zone.
- Updated NS at registrar\
- Recreated A-alias records\
- Validated global propagation
- Always verify hosted zone β registrar sync\
- CloudFront TLS depends on correct DNS\
- DNS validation using public recursive resolvers:
- Google DNS (8.8.8.8) β authoritative and successful
- Cloudflare DNS (1.1.1.1) β may be filtered by local ISP/WiFi networks
- OAC instead of OAI (modern secure origin auth)\
- BucketOwnerEnforced mode\
- Dual A-alias routing\
- Split TTL caching\
- Strict IAM OIDC roles\
- Terraform with create_before_destroy for ACM\
- Multi-line, comment-structured Terraform (Ruslan AWS style)
- Real production static hosting\
- Strong AWS infrastructure knowledge\
- Secure CI/CD\
- Real-world DNS debugging\
- Clean Terraform architecture
This screenshot shows the public RD Service Pros website as delivered through CloudFront.
It demonstrates the final look-and-feel of the static site: branding, layout, navigation menu, and main call-to-action for customers.
This view shows the CloudFront distribution that serves the static site.
You can see the custom domain names (rdservicepros.com and www.rdservicepros.com), attached ACM certificate, default root object, and general settings used for the CDN.
This screenshot highlights the S3 bucket permissions for rdservicepros-site.
Public access is fully blocked and the bucket policy only allows access from CloudFront via Origin Access Control (OAC), so the website is not directly exposed from S3.
Here you can see the actual website assets stored in S3.
The bucket hosts index.html and an assets/ folder with CSS, JavaScript, and images that are synchronized from the site/ directory using the GitHub Actions workflow.
This screenshot shows a successful run of the βDeploy static site to AWSβ GitHub Actions workflow.
The pipeline authenticates to AWS via OIDC, syncs static assets to S3 with different cache policies, and triggers a CloudFront cache invalidation so new content becomes visible quickly.
The final screenshot demonstrates DNS resolution for rdservicepros.com using dig against Google Public DNS (8.8.8.8).
It confirms that the apex domain correctly resolves to the CloudFront IPs, proving that Route 53 and CloudFront are wired together as expected.
- Released under the MIT License β see
LICENSEfor full text. - Β© Ruslan Dashkin (βπ Ruslan AWSβ).
- Branding name βπ Ruslan AWSβ and related visuals may not be reused, redistributed, or rebranded without explicit permission.





