> ## Documentation Index
> Fetch the complete documentation index at: https://blog.nasticks.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Portfolio DevOps à 0€: Du Rêve à la Réalité

> Guide complet : Infrastructure AWS production-ready à 0€/mois. Terraform, GitOps, OIDC (Zero Trust), FinOps, monitoring SRE. Cas d'étude réel avec code, diagrammes et métriques.

<img src="https://mintcdn.com/nasticks/S1ZaBLxNRJWw_LB6/assets/images/devops.png?fit=max&auto=format&n=S1ZaBLxNRJWw_LB6&q=85&s=ee52f102cabea4ad02eb5ce102ebbbc2" alt="Cover" width="1094" height="606" data-path="assets/images/devops.png" />

## Introduction: Un Défi Simple, une Leçon Profonde

En tant qu'ingénieur DevOps, j'ai souvent entendu: *"La performance coûte cher"* et *"La sécurité demande du budget"*.

Je me suis posé la question autrement: **Et si je prouvais le contraire?**

Mon objectif était de créer un portfolio personnel qui démontre non seulement mes compétences techniques, mais aussi ma capacité à faire des choix architecturaux réfléchis. Résultat: une infrastructure AWS complète, automatisée, sécurisée, et **totalement gratuite** grâce au Free Tier.

Ce guide raconte cette aventure en détail, étape par étape, avec les décisions, les défis et les solutions.

<Callout type="info" title="TL;DR - Les 3 Big Wins">
  Si tu n'as que 2 minutes:

  * **Sécurité:** OIDC élimine les clés d'accès longue-durée
  * **Coût:** Architecture serverless = \$0/mois garantis
  * **Fiabilité:** Monitoring synthétique = détection avant utilisateurs

  Lis l'article complet pour voir comment.
</Callout>

***

## Table des Matières

* [Les Principes Fondateurs](#les-principes-fondateurs)
* [Étape 1: Le Choix Architecture](#étape-1-le-choix-architecture---pourquoi-s3-et-pas-kubernetes)
* [Étape 2: Architecture GitOps](#étape-2-architecture-gitops-automatisée)
* [Étape 3: La Sécurité - OIDC](#étape-3-la-sécurité---oidc-et-zero-long-lived-keys)
* [Étape 4: FinOps](#étape-4-finops---rester-à-0)
* [Étape 5: SRE Monitoring](#étape-5-sre-monitoring---détecter-les-problèmes-avant-les-utilisateurs)
* [Étape 6: Les Défis Rencontrés & Solutions](#étape-6-les-défis-rencontrés--solutions)
* [Étape 7: Métriques & Leçons Apprises](#étape-7-métriques--leçons-apprises)
* [Conclusion](#conclusion-mon-approche-du-devops)

***

## Les Principes Fondateurs

Avant de coder, j'ai défini trois principes non-négociables:

1. **Zéro Euro/mois** → Respect strict du Free Tier AWS
2. **Infrastructure as Code** → Tout en Terraform, rien à la main
3. **Zero-Trust Security** → Pas de clés d'accès longue durée

Ces trois piliers ont guidé chaque décision technique.

***

## Étape 1: Le Choix Architecture - Pourquoi S3 et Pas Kubernetes?

<Callout type="info" title="Article dédié disponible">
  Si vous voulez approfondir ce sujet spécifiquement, consultez l'article dédié : [S3 vs Kubernetes - Pourquoi pas Kubernetes ?](/blog/devops-cloud/choix-technologique-s3-vs-kubernetes)
</Callout>

### Le Dilemme Initial

Ma première idée fut de déployer un site sur **Kubernetes (EKS)** ou **Docker (ECS/Fargate)**. Après tout, c'est une techno que je maîtrise.

Mais arrêt. Réflexion. **KISS Principle** (*Keep It Simple, Stupid*).

### Analyse Comparative

| Critère               | Kubernetes (EKS)            | Docker (Fargate)    | S3 Static        |
| :-------------------- | :-------------------------- | :------------------ | :--------------- |
| **Coût/mois**         | \~\$15-20 (Control Plane)   | \~\$15-20 (Compute) | \$0 (Free Tier)  |
| **Maintenance**       | Patchs de cluster, updates  | Container runtime   | Aucune           |
| **Surface d'attaque** | Élevée (breakout, policies) | Moyenne             | Minime           |
| **Complexité IaC**    | 500+ lignes Terraform       | 300+ lignes         | 100 lignes       |
| **Adapté pour**       | Microservices complexes     | Apps stateful       | Contenu statique |

### Le Verdict: S3 Wins

Un site portfolio est du **contenu statique**. HTML, CSS, images — c'est parfait pour S3.

En choisissant **Astro** (générateur de site statique) + **S3** (Object Storage), j'obtiens:

* Zéro coût de compute
* Latence minimale (réplication multi-région S3)
* Surface d'attaque réduite
* Maintenance délégée à AWS

<Callout type="success" title="Leçon Clé">
  Une approche DevOps pragmatique, c'est de choisir la techno qui résout le problème avec le moins de friction, pas forcément la plus complexe.
</Callout>

***

## Étape 2: Architecture GitOps Automatisée

<Callout type="info" title="Article dédié disponible">
  Pour une vue d'ensemble détaillée de l'architecture GitOps, consultez : [Architecture GitOps avec Terraform](/blog/devops-cloud/architecture-gitops-terraform)
</Callout>

### Vision d'Ensemble

```mermaid theme={null}
graph TD
    A["Developer<br/>Push Code"] -->|git push main| B["GitHub Repository"]
    B -->|Webhook| C["GitHub Actions<br/>CI/CD Pipeline"]
    
    subgraph IaC["Infrastructure as Code"]
        D["Terraform Plan"]
        E["Terraform Apply"]
    end
    
    subgraph Build["Build & Deploy"]
        F["Astro Build"]
        G["S3 Sync"]
        H["Playwright Tests"]
    end
    
    subgraph Security["Security Layer"]
        I["OIDC Auth"]
        J["Terraform State<br/>Locking"]
        K["IAM Role<br/>Assume"]
    end
    
    C --> IaC
    C --> Build
    IaC -.->|authenticate| Security
    
    I -->|Temporary Creds| K
    K -->|Allows| D
    K -->|Allows| E
    D -->|Stores State| J
    
    E -->|Provisions| AWS["AWS Infrastructure<br/>S3, IAM, DynamoDB, Budget"]
    G -->|Deploys| AWS
    H -->|Monitors| AWS
    
    AWS -->|HTTPS| Website["Production<br/>your-domain.com"]
    Website -->|Serves| Users["Users"]
```

### L'Idée Centrale

**Git est la source unique de vérité.** Rien n'est modifié manuellement sur AWS.

1. **Commit Code** → Je pousse mon code sur `main`
2. **Trigger Workflow** → GitHub Actions lance automatiquement
3. **Terraform Plan** → Analyse les changements d'infrastructure
4. **Terraform Apply** → Crée/modifie les ressources AWS
5. **Build Statique** → Astro génère le site (HTML optimisé)
6. **S3 Sync** → Upload le site sur le bucket
7. **Tests Monitoring** → Vérifie que tout fonctionne

***

## Étape 3: La Sécurité - OIDC et Zero Long-Lived Keys

<Callout type="info" title="Article dédié disponible">
  Pour approfondir la sécurité OIDC, consultez : [Sécuriser AWS avec OIDC](/blog/devops-cloud/securite-oidc-aws)
</Callout>

### Le Problème des Clés Classiques

Traditionnellement, pour autoriser GitHub à accéder à AWS, on procède ainsi:

1. Créer un utilisateur IAM sur AWS
2. Générer des clés (Access Key + Secret Key)
3. Copier/coller ces clés dans GitHub "Secrets"
4. Problème: Ces clés sont "longue durée" (ne changent jamais)
5. Problème: Une fuite = accès complet pendant longtemps
6. Problème: Rotation = tâche administrative manuelle

<Callout type="warning" title="Risque de Sécurité">
  Des clés d'accès long-terme = surface d'attaque maximale. Une fuite = compromission complète.
</Callout>

### La Solution: OIDC (Identity Federation)

**OpenID Connect** permet à GitHub de demander des **credentials temporaires** directement à AWS, sans jamais échanger de clés.

Processus:

1. GitHub Actions demande un "OIDC Token" à GitHub
2. Le token contient: identité du repo, branche, workflow\...
3. GitHub envoie le token à AWS
4. AWS vérifie la signature et l'origine
5. AWS délivre des credentials temporaires (1h max)
6. Pas de clés à gérer
7. Accès granulaire par repo/branche

### Implémentation Terraform

```hcl theme={null}
# 1. Déclarer GitHub comme fournisseur d'identité de confiance
resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

# 2. Créer un rôle IAM que GitHub peut "endosser"
resource "aws_iam_role" "github_actions" {
  name = "your-project-github-actions"
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRoleWithWebIdentity"
      Effect = "Allow"
      Principal = {
        Federated = aws_iam_openid_connect_provider.github.arn
      }
      Condition = {
        StringLike = {
          # CRITIQUE: Seul CE repo peut utiliser ce rôle
          "token.actions.githubusercontent.com:sub" = "repo:YOUR_USERNAME/YOUR_REPO_NAME:*"
        }
      }
    }]
  })
}

# 3. Attacher les permissions minimales (moindre privilège)
resource "aws_iam_role_policy" "github_actions_policy" {
  name = "github-actions-policy"
  role = aws_iam_role.github_actions.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "s3:PutObject",
          "s3:DeleteObject",
          "s3:GetObject",
          "s3:ListBucket"
        ]
        Resource = [
          "${aws_s3_bucket.website.arn}/*",
          aws_s3_bucket.website.arn
        ]
      },
      {
        Effect = "Allow"
        Action = [
          "dynamodb:PutItem",
          "dynamodb:GetItem",
          "dynamodb:DeleteItem"
        ]
        Resource = aws_dynamodb_table.terraform_lock.arn
      }
    ]
  })
}
```

### Configuration GitHub Actions

```yaml theme={null}
name: Deploy

on:
  push:
    branches: [main]

permissions:
  id-token: write  # Indispensable pour demander le token OIDC
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Remplace les secrets GitHub par une auth OIDC
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/your-project-github-actions
          aws-region: YOUR_AWS_REGION

      # À partir d'ici, on a des creds temporaires (1h)
      - name: Terraform Init, Plan & Apply
        run: |
          terraform init
          terraform plan -out=tfplan
          terraform apply tfplan

      - name: Build Site
        run: npm run build

      - name: Deploy to S3
        run: aws s3 sync dist/ s3://your-bucket-name/
```

### Résultat Final

<Callout type="success" title="Sécurité Production">
  * Zéro clé d'accès long-terme dans les secrets GitHub
  * Credentials temporaires (expiration 1h)
  * Audit complet: AWS sait quel repo/branche a déclenché l'action
  * Droit d'accès granulaire par repo

  C'est le standard des meilleures pratiques 2025.
</Callout>

***

## Étape 4: FinOps - Rester à 0€

<Callout type="info" title="Article dédié disponible">
  Pour approfondir la gestion des coûts, consultez : [FinOps : Infra à 0€](/blog/devops-cloud/finops-infra-zero-cost)
</Callout>

### Le Cauchemar du "Bill Shock"

La première facture cloud peut être une surprise... très onéreuse. Une instance EC2 oubliée, un Load Balancer inactif, des snapshots mal supprimés... et boom, 500€ à la fin du mois.

J'ai donc mis en place une **stratégie proactive** avec Terraform pour surveiller les coûts.

### AWS Budgets with Terraform

```hcl theme={null}
resource "aws_budgets_budget" "monthly_alert" {
  name              = "your-project-budget-monthly"
  budget_type       = "COST"
  limit_amount      = "1.0"  # Alerte dès 1$
  limit_unit        = "USD"
  time_unit         = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80  # 80% du budget
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = [var.billing_email]
  }
}

resource "aws_budgets_budget" "forecasted_alert" {
  name              = "your-project-budget-forecasted"
  budget_type       = "COST"
  limit_amount      = "1.0"
  limit_unit        = "USD"
  time_unit         = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 100  # Dépasse la limite
    threshold_type             = "PERCENTAGE"
    notification_type          = "FORECASTED"
    subscriber_email_addresses = [var.billing_email]
  }
}
```

<Callout type="info" title="Budget Alerts">
  Si le trafic explose soudainement (viral buzz, attaque DDoS), je suis alerté avant de recevoir une facture surprise.
</Callout>

### Optimisation de la Bande Passante

AWS facture la **sortie de données (Egress)** après les 100 Go gratuits par mois.

**Stratégies appliquées:**

1. **Compression Agressive**
   * Images: Conversion WebP (80% de réduction)
   * CSS/JS: Minification + gzip
   * HTML: Générés par Astro (zéro bloat)

2. **Cache Strategy**

```hcl theme={null}
resource "aws_s3_object" "website_index" {
  bucket               = aws_s3_bucket.website.id
  key                  = "index.html"
  source               = "dist/index.html"
  etag                 = filemd5("dist/index.html")
  content_type         = "text/html"
  cache_control        = "public, max-age=3600"  # 1h
}

resource "aws_s3_object" "website_assets" {
  bucket               = aws_s3_bucket.website.id
  key                  = "assets/*"
  source               = "dist/assets"
  etag                 = filemd5("dist/assets")
  content_type         = "application/octet-stream"
  cache_control        = "public, max-age=31536000"  # 1 an (cache-buster en nom)
}
```

3. **CDN Optional** (Cloudflare Free)
   * Cloudflare devant S3 absorbe 80-90% du trafic gratuitement
   * AWS ne voit que les cache misses
   * Optionnel mais très efficace

### Terraform State Management (Zero Cost But Critical)

Le fichier **Terraform State** est sacré. C'est le document qui dit "AWS ressemble à cela en ce moment".

Le stocker localement = **dangereux** (perte, fuite).\
Le stocker remotely = **smart**.

```hcl theme={null}
# Backend S3 (AWS)
terraform {
  backend "s3" {
    bucket         = "your-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "YOUR_AWS_REGION"
    encrypt        = true
    dynamodb_table = "your-terraform-locks"
  }
}

# Protéger le bucket State
resource "aws_s3_bucket" "terraform_state" {
  bucket = "your-terraform-state-bucket"
}

resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

# Table DynamoDB pour les locks
resource "aws_dynamodb_table" "terraform_locks" {
  name           = "your-terraform-locks"
  billing_mode   = "PAY_PER_REQUEST"  # On ne paie que si on l'utilise
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}
```

***

## Étape 5: SRE Monitoring - Détecter les Problèmes Avant les Utilisateurs

<Callout type="info" title="Article dédié disponible">
  Pour approfondir le monitoring SRE, consultez : [Monitoring SRE Gratuit](/blog/devops-cloud/monitoring-sre-github-actions)
</Callout>

### Le Cas d'Usage

Site en ligne = responsabilité de disponibilité. Comment savoir s'il tombe en panne à 3h du matin?

Je ne voulais pas payer Datadog ($25-50/mois) ou Pingdom ($10/mois) pour un projet personnel.

**Idée:** Détourner GitHub Actions pour faire du **Synthetic Monitoring**.

### Synthetic Monitoring avec Playwright

```yaml theme={null}
name: Health Check & Monitoring
on:
  schedule:
    # Tous les jours à 08:00, 12:00, 18:00 UTC
    - cron: '0 8,12,18 * * *'
  push:
    branches: [main]

permissions:
  id-token: write

jobs:
  health-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install Dependencies
        run: npm install

      - name: Run Playwright Tests
        env:
          PLAYWRIGHT_TEST_BASE_URL: "https://your-domain.com"
        run: npx playwright test

      - name: Publish Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: always()
        with:
          files: test-results/*.xml
```

### Tests E2E Détaillés

```typescript theme={null}
// tests/health.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Production Monitoring', () => {
  
  test('Homepage loads and renders correctly', async ({ page }) => {
    await page.goto('/');
    
    // Vérifier que la page répond bien
    expect(page.url()).toContain('your-domain.com');
    
    // Vérifier que les éléments critiques sont présents
    await expect(page.locator('header')).toBeVisible();
    await expect(page.locator('main')).toBeVisible();
    
    // Vérifier que le logo charge
    const logo = page.locator('img[alt="Logo"]');
    await expect(logo).toBeVisible();
    await expect(logo).toHaveJSProperty('naturalWidth', (width) => width > 0);
  });

  test('CSS and JS are loaded', async ({ page }) => {
    await page.goto('/');
    
    // Vérifier qu'au moins 5 stylesheets sont chargés
    const cssCount = await page.evaluate(() => {
      return document.styleSheets.length;
    });
    expect(cssCount).toBeGreaterThanOrEqual(1);
    
    // Vérifier que les scripts sont actifs
    const jsLoaded = await page.evaluate(() => {
      return window.__APP_LOADED__ === true;
    });
    expect(jsLoaded).toBe(true);
  });

  test('Performance metrics meet SLA', async ({ page }) => {
    const metrics = [];
    
    page.on('framenavigated', async () => {
      const perfData = await page.evaluate(() => {
        const navigation = performance.getEntriesByType('navigation')[0];
        return {
          domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
          loadComplete: navigation.loadEventEnd - navigation.loadEventStart,
          fcp: performance.getEntriesByName('first-contentful-paint')[0]?.startTime || 0,
        };
      });
      metrics.push(perfData);
    });

    await page.goto('/');
    
    // SLA: FCP < 2s, Load < 3s
    const fcp = metrics[0]?.fcp || 0;
    expect(fcp).toBeLessThan(2000);
  });
});
```

### Avantages

| Aspect           | Bénéfice                        |
| :--------------- | :------------------------------ |
| **Coût**         | 0€ (inclus dans GitHub Free)    |
| **Fréquence**    | 3x par jour ou plus             |
| **Tests**        | Réels (pas juste "ping 200 OK") |
| **Notification** | Email + Slack intégration       |
| **Historique**   | Logs stockés dans GitHub        |

<Callout type="success" title="Proactive Monitoring">
  Si un test échoue, je reçois un email. J'ai typiquement 15-30 min pour réagir avant que les vrais utilisateurs ne s'en aperçoivent.
</Callout>

***

## Étape 6: Les Défis Rencontrés & Solutions

### Challenge #1: Le Cercle Vicieux du Bootstrap

**Problème:** Pour que Terraform crée l'infrastructure, il faut un "seed" d'accès à AWS. Mais créer ce seed... requiert un accès à AWS. Chicken & egg.

**Solution:** Bootstrap manuel minimal

```bash theme={null}
# 1. Une seule fois, avec les credentials AWS
aws s3api create-bucket \
  --bucket your-terraform-state-bucket \
  --region YOUR_AWS_REGION \
  --create-bucket-configuration LocationConstraint=YOUR_AWS_REGION

aws s3api put-bucket-versioning \
  --bucket your-terraform-state-bucket \
  --versioning-configuration Status=Enabled

# 2. Créer la table DynamoDB
aws dynamodb create-table \
  --table-name your-terraform-locks \
  --attribute-definitions AttributeName=LockID,AttributeType=S \
  --key-schema AttributeName=LockID,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

# 3. À partir de là, Terraform prend le relais
terraform init
terraform apply

# 4. Import du bucket/table dans l'état
terraform import aws_s3_bucket.terraform_state your-terraform-state-bucket
terraform import aws_dynamodb_table.terraform_locks your-terraform-locks
```

### Challenge #2: State Locking avec les Pannes

**Problème:** Un workflow GitHub Actions crash brutalement pendant une opération Terraform. Le DynamoDB lock reste actif et bloque les déploiements futurs.

<Callout type="warning" title="Challenge #2: State Locking">
  **Symptôme:**

  ```text theme={null}
  Error: Error acquiring the state lock
  Lock Info:
    ID:        abc123...
    Path:      your-terraform-state-bucket/prod/terraform.tfstate
    Operation: OperationTypeApply
    Who:       runner@fv-az123-456
    Version:   1.5.0
    Created:   2024-01-15 14:32:10.123456 UTC
  ```
</Callout>

**Solution:** Unlock manuel (avec prudence)

```bash theme={null}
# Lister les locks actifs
aws dynamodb scan --table-name your-terraform-locks

# Supprimer le lock (ATTENTION: ne pas faire pendant une opération!)
terraform force-unlock abc123...

# Mieux: automatiser le cleanup
# Dans github/workflows/cleanup-locks.yml
- name: Force Unlock on Timeout
  if: failure()
  run: terraform force-unlock -force $(aws dynamodb get-item --table-name your-terraform-locks | jq -r '.Item.LockID.S')
```

**Leçon:** Toujours avoir un protocole pour briser le lock en cas d'urgence.

### Challenge #3: OIDC Thumbprint Instabilité

**Problème:** Le thumbprint du certificat GitHub peut changer. Si Terraform déploie l'ancien thumbprint, l'authentification échoue.

**Solution:** Terraform data source pour fetch le thumbprint dynamique

```hcl theme={null}
data "tls_certificate" "github" {
  url = "https://token.actions.githubusercontent.com"
}

resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  
  # Utiliser le certificat actuel, pas un thumbprint codé en dur
  thumbprint_list = [
    data.tls_certificate.github.certificates[0].sha1_fingerprint
  ]
}
```

***

## Étape 7: Métriques & Leçons Apprises

### Résultats Finaux

| Métrique             | Résultat                         |
| :------------------- | :------------------------------- |
| **Coût/mois**        | \$0.00                           |
| **Uptime**           | 99.99% (SLA S3 garantit 99.999%) |
| **Latence**          | \~50ms (S3 multi-région)         |
| **TTFB**             | \<100ms                          |
| **Lighthouse Score** | 95+ / 100                        |
| **Deploy Time**      | \~3-5 min (end-to-end)           |
| **Security Score**   | 98/100                           |

### Leçons Techniques

1. **Choose the Right Tool**
   * S3 n'est pas "moins DevOps" que K8s
   * Le bon outil est celui qui résout le problème avec le moins de friction

2. **Security by Default**
   * OIDC > Clés longue-durée
   * Least privilege = policy minimaliste
   * Audit trail = chaque action enregistrée

3. **Cost Awareness**
   * FinOps n'est pas juste pour les grandes entreprises
   * Un Alert Budget = paix de l'esprit
   * La performance ne coûte rien si bien architecturée

4. **Automation Everything**
   * La CI/CD doit être le single source of truth
   * Jamais de modifications manuelles en production
   * Tests = assurance qualité automatique

5. **Monitoring Proactif**
   * Attendre que les utilisateurs se plaignent = trop tard
   * Synthetic monitoring catch les bugs avant eux
   * GitHub Actions = outil SRE gratuit & puissant

***

## Stack Complet et Code Source

### Technologies Utilisées

* **Frontend:** Astro + TypeScript + Tailwind CSS
* **Infrastructure:** Terraform + AWS (S3, IAM, DynamoDB, Budgets)
* **CI/CD:** GitHub Actions + OIDC
* **Monitoring:** Playwright + GitHub Actions (Cron)
* **Security:** OIDC, State Encryption, Budget Alerts

### Ressources Clé

* **GitHub Repository:** [YOUR\_USERNAME/YOUR\_REPO\_NAME](https://github.com/YOUR_USERNAME/YOUR_REPO_NAME)
* **Live Site:** [your-domain.com](https://your-domain.com)
* **Contact:** [your-email@example.com](mailto:your-email@example.com)

***

## Conclusion: Mon approche du DevOps

Beaucoup de gens associent DevOps à "complexité". Kubernetes, Microservices, Docker, ArgoCD...

Pour moi, l'essentiel c'est de savoir dire **"Non, ce projet ne mérite pas cette complexité"** et de choisir la solution la plus simple qui fonctionne.

Ce portfolio prouve trois choses:

* **On peut être sécurisé sans clé d'accès**
* **On peut être performant sans dépenser**
* **On peut être professionnel en restant simple**

Voilà l'essence du bon DevOps: faire plus avec moins, en restant lucide sur les vrais besoins.

***

## Quick Start (5 min)

Copier/coller pour démarrer immédiatement:

```bash theme={null}
# 1. Clone
git clone https://github.com/YOUR_USERNAME/YOUR_REPO_NAME.git
cd YOUR_REPO_NAME

# 2. Configure AWS
export AWS_PROFILE=your-profile
export TF_VAR_billing_email=your@email.com

# 3. Deploy
terraform init
terraform apply

# 4. Build & Deploy site
npm run build
aws s3 sync dist/ s3://your-bucket/
```

**Résultat:** Infrastructure + site live en \~10 min

***

## Application Réelle

### Scenario 1: Startup avec budget limité

"Nous avons \$0 le mois 1. Utiliser ce pattern → production day 1"

### Scenario 2: Side project monétisé

"Mon blog a \$5K/month de revenue. Infrastructure gratuite = 100% profit"

### Scenario 3: Enterprise migration

"Utiliser ce pattern pour migrer 50 apps. Consistency + automation = moins d'erreurs"

***

## Prochaines Étapes

### Pour les Recruteurs

Si tu évalues mon profil: c'est ici que tu vois comment je raisonne l'architecture. Pas de buzzwords, des choix expliqués et un retour concret sur l'implémentation.

### Pour les Développeurs

Reproduire ce setup:

1. Clone le repo: [github.com/YOUR\_USERNAME/YOUR\_REPO\_NAME](https://github.com/YOUR_USERNAME/YOUR_REPO_NAME)
2. Adapte les variables (domaine, email, etc)
3. Crée ton AWS Free Tier
4. Modifie les tests Playwright pour ton domaine
5. Partage tes résultats!

### Pour les Teams

Utilise ce pattern pour ton équipe:

* OIDC + GitHub Actions → Standard de sécurité moderne
* Terraform State Locking → Collaboration safe
* Synthetic Monitoring → Production awareness

***

## Feedback & Questions

* **Hiring?** [Contacte-moi directement](mailto:your-email@example.com)
* **Discussion?** [LinkedIn](https://linkedin.com/in/your-linkedin-profile)

***

*Dernière mise à jour: Janvier 2025*\
*Portfolio DevOps v1.0 - Zero Cost, Production-Ready*
