diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 81b6ab3..bd463dc 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,60 +1,60 @@ ---- - ################################# - ################################# - ## Super Linter GitHub Actions ## - ################################# - ################################# - name: Lint Code Base +# --- +# ################################# +# ################################# +# ## Super Linter GitHub Actions ## +# ################################# +# ################################# +# name: Lint Code Base - ############################# - # Start the job on all push # - ############################# - on: - push: - branches-ignore: [main] - # Remove the line above to run when pushing to master +# ############################# +# # Start the job on all push # +# ############################# +# on: +# push: +# branches-ignore: [main] +# # Remove the line above to run when pushing to master - ############### - # Set the Job # - ############### - jobs: - build: - # Name the Job - name: Lint Code Base - # Set the agent to run on - runs-on: ubuntu-latest +# ############### +# # Set the Job # +# ############### +# jobs: +# build: +# # Name the Job +# name: Lint Code Base +# # Set the agent to run on +# runs-on: ubuntu-latest - ############################################ - # Grant status permission for MULTI_STATUS # - ############################################ - permissions: - contents: read - packages: read - statuses: write +# ############################################ +# # Grant status permission for MULTI_STATUS # +# ############################################ +# permissions: +# contents: read +# packages: read +# statuses: write - ################## - # Load all steps # - ################## - steps: - ########################## - # Checkout the code base # - ########################## - - name: Checkout Code - uses: actions/checkout@v3 - with: - # Full git history is needed to get a proper - # list of changed files within `super-linter` - fetch-depth: 0 +# ################## +# # Load all steps # +# ################## +# steps: +# ########################## +# # Checkout the code base # +# ########################## +# - name: Checkout Code +# uses: actions/checkout@v3 +# with: +# # Full git history is needed to get a proper +# # list of changed files within `super-linter` +# fetch-depth: 0 - ################################ - # Run Linter against code base # - ################################ - - name: Lint Code Base - uses: super-linter/super-linter@v5 - env: - VALIDATE_ALL_CODEBASE: false - DEFAULT_BRANCH: main - VALIDATE_EDITORCONFIG: true - LINTER_RULES_PATH: / - EDITORCONFIG_FILE_NAME: .editorconfig - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# ################################ +# # Run Linter against code base # +# ################################ +# - name: Lint Code Base +# uses: super-linter/super-linter@v5 +# env: +# VALIDATE_ALL_CODEBASE: false +# DEFAULT_BRANCH: main +# VALIDATE_EDITORCONFIG: true +# LINTER_RULES_PATH: / +# EDITORCONFIG_FILE_NAME: .editorconfig +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 6dea8e1..fae8082 100644 --- a/.gitignore +++ b/.gitignore @@ -401,3 +401,8 @@ FodyWeavers.xsd .env # IdentityServer signing keys - never commit key material src/Services/Identity/Identity.API/keys/ + +# K8s cert binaries — generated by src/certificates/generate-certs.sh +k8s/base/00-core/certs/*.pfx +k8s/base/00-core/certs/*.crt +k8s/base/00-core/certs/*.key diff --git a/Diagram.png b/Diagram.png new file mode 100644 index 0000000..7cf110e Binary files /dev/null and b/Diagram.png differ diff --git a/README.md b/README.md index 9a58df9..a790fc8 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ - [Technology Stack](#technology-stack) - [Data Architecture](#data-architecture) - [Running the Application](#running-the-application) +- [Kubernetes Deployment](#kubernetes-deployment) - [Design Patterns](#design-patterns) - [Observability](#observability) - [Project Structure](#project-structure) @@ -37,38 +38,15 @@ EshopMicroservices is a hands-on reference implementation that shows how to buil The system follows a loosely coupled microservices architecture. Each service owns its data, exposes its own API, and communicates with other services either synchronously via gRPC or asynchronously via a shared message bus (RabbitMQ). -``` - ┌─────────────────────────────────────────┐ - │ Client Apps │ - └───────────────────┬─────────────────────┘ - │ HTTP/HTTPS - ┌───────────────────────────────────▼───────────────────────────────────────────┐ - │ API Gateway (YARP) │ - │ routing · rate limiting · reverse │ - │ proxy │ - └────┬──────────┬──────────────────┬───────────────┬──────────┬────────────┬────┘ - │ │ │ │ │ │ - ┌────▼────┐ ┌───▼───┐ ┌───▼─────┐ ┌────▼────┐┌────▼─────┐ ┌────▼──────┐ - │Catalog │ │Basket │ │Discount │ │ Order- ││ Order- │ │ Identity │ - │ │ │ │◄─────────────gRPC │ │ command ││ query │ │ (OIDC) │ - └────┬────┘ └──┬────┘ └──────┬──┘ └───┬─────┘└─────┬────┘ └──────┬────┘ - │ │ RabbitMQ │ │ │ │ - │ │────────────[checkout]│───────────│────────────│ │ - ┌────▼───┐┌────▼──────┐ ┌─────┐ ┌─────▼──┐ ┌───▼───────┐┌───▼───────┐┌────▼──────┐ - │Post- ││PostgreSQL │─│Redis│ │SQLite │ │PostgreSQL ││PostgreSQL ││PostgreSQL │ - │greSQL ││ │ └─────┘ └────────┘ │ ││ ││ │ - └────────┘└───────────┘ └───────────┘└───────────┘└───────────┘ - - Docker Compose (all containers) -``` +![System Architecture](Diagram.png) ### Architectural Layers | Layer | Components | |---|---| -| API Gateway | YARP reverse proxy — single entry point | +| API Gateway | YARP reverse proxy; single entry point | | Microservices | Catalog, Basket, Discount, Ordering, Identity | -| Messaging | RabbitMQ + MassTransit — async pub/sub | +| Messaging | RabbitMQ + MassTransit; async pub/sub | | Data | Dedicated data store per service | | Infrastructure | Docker Compose orchestration | @@ -86,7 +64,7 @@ When a basket is checked out, an HTTP request is sent to the Order Command servi ### Catalog Service Manages the product catalogue. Read-heavy and optimised for query throughput. -- **Pattern:** Vertical Slice Architecture — each feature lives in its own folder with its own command/query, handler, and validator +- **Pattern:** Vertical Slice Architecture; each feature lives in its own folder with its own command/query, handler, and validator - **CQRS:** Commands (writes) and queries (reads) are separated using MediatR - **Database:** Marten document database over PostgreSQL for flexible product schemas - **Validation:** FluentValidation pipeline behaviour validates all incoming requests @@ -106,7 +84,7 @@ Simple coupon management service, consumed exclusively via gRPC. - **No public HTTP API:** Only accessible via gRPC from internal services ### Ordering Command Service -The most complex service — demonstrates full Domain-Driven Design and Clean Architecture. +The most complex service; demonstrates full Domain-Driven Design and Clean Architecture. - **Domain layer:** `Order` aggregate root, `OrderItem` entities, `Address` and `Money` value objects - **Application layer:** CQRS handlers via MediatR; domain events raised and handled in-process and publishes events to RabbitMQ @@ -133,7 +111,7 @@ Handles authentication and authorisation across the system. Single entry point for all client requests. - Built on **YARP** (Yet Another Reverse Proxy) by Microsoft -- Routing configured in `appsettings.json` — no code changes needed for new routes +- Routing configured in `appsettings.json`; no code changes needed for new routes - Handles rate limiting and can aggregate responses from multiple upstream services --- @@ -216,6 +194,139 @@ This builds all images and starts every service, database, RabbitMQ, and the obs --- +## Kubernetes Deployment + +The project ships with a production-grade Kubernetes configuration under `k8s/`, managed with **Kustomize** (built into `kubectl`). It targets local clusters (minikube / kind / Docker Desktop) via the `overlays/local` overlay and is structured so a `production` overlay can be added later without touching the base. + +### Prerequisites + +- `kubectl` 1.27+ (includes Kustomize) +- A local cluster: Docker Desktop with Kubernetes enabled +- `openssl` (for certificate generation) + +### Quick Start + +#### Docker Desktop (recommended on macOS / Windows) + +Enable Kubernetes in **Docker Desktop → Settings → Kubernetes → Enable Kubernetes**, then: + +```bash +# ── First time only ──────────────────────────────────────────────────────────── + +# 1. Install the nginx Ingress controller +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/cloud/deploy.yaml + +# 2. Build service images +cd src && docker compose build && cd .. + +# 3. Generate TLS certificates (valid 365 days; re-run only if they expire) +mkdir -p k8s/base/00-core/certs +cd src/certificates && bash generate-certs.sh && cd ../.. + +# 4. Deploy the full stack +bash k8s/scripts/apply.sh local + +# 5. Add /etc/hosts entries +# The ingress IP is stable across eshop redeployments. +# Only redo this if you fully reset the cluster on your local machine +# since that assigns a new LoadBalancer IP. +bash k8s/scripts/hosts-setup.sh | sudo tee -a /etc/hosts + +## +# If postman or curl cant connect to the https try to run the following command in ca.crt folder + +## Mac machine +sudo security add-trusted-cert -d -r trustRoot \ +-k /Library/Keychains/System.keychain \ +ca.crt + +## Windows machine +Import-Certificate ` + -FilePath "C:\path\to\ca.crt" ` + -CertStoreLocation Cert:\LocalMachine\Root +# ── Day-to-day ───────────────────────────────────────────────────────────────── + +# After changing code, rebuild the affected image(s) then re-deploy: +cd src && docker compose build && cd .. +bash k8s/scripts/apply.sh local + +# To tear down: +# Remove (keeps PVC data intact for next deploy) +bash k8s/scripts/teardown.sh local + +# Remove + wipe all data +bash k8s/scripts/teardown.sh local --wipe-data +``` + +You can check the deployments with this command + +```bash +k9s -n eshop-microservices +``` + +### Accessing the Services + +Once deployed, all services are reachable via nginx Ingress on `*.eshop.local`: + +| Host | Service | +|---|---| +| `https://api.eshop.local` | API Gateway (entry point for all API calls) | +| `https://identity.eshop.local` | Identity / OIDC server | +| `https://grafana.eshop.local` | Grafana dashboards (Prometheus + Loki + Jaeger pre-provisioned) | +| `https://kibana.eshop.local` | Kibana (Elasticsearch log viewer) | +| `https://jaeger.eshop.local` | Jaeger distributed tracing UI | +| `https://prometheus.eshop.local` | Prometheus metrics | +| `https://mailpit.eshop.local` | Mailpit email testing UI | +| `https://rabbitmq.eshop.local` | RabbitMQ management UI (guest / guest) | + +### Directory Layout + +``` +k8s/ +├── base/ +│ ├── 00-core/ # Namespace, RBAC, Secrets, ConfigMaps, certs/ +│ ├── 01-databases/ # PostgreSQL ×5, Redis, RabbitMQ (StatefulSets + PVCs) +│ ├── 02-observability/ # Elasticsearch, Kibana, OTEL Collector, Jaeger, +│ │ # Prometheus, Loki, Grafana +│ ├── 03-mail/ # Mailpit +│ ├── 04-services/ # 8 microservice Deployments, NetworkPolicies, +│ │ # PodDisruptionBudgets, HPAs +│ └── 05-ingress/ # nginx Ingress rules +└── overlays/ + ├── local/ # Lighter Elasticsearch limits for dev machines + └── production/ # Placeholder; patch storage class, replicas, image tags here +``` + +### Certificate Management + +Every service uses its own TLS certificate signed by an internal CA. The `generate-certs.sh` script already knows about the k8s certs directory; running it populates both `src/certificates/` and `k8s/base/00-core/certs/` automatically. + +```bash +# Regenerate certs (e.g. after they expire or you add a service) +mkdir -p k8s/base/00-core/certs +cd src/certificates && ./generate-certs.sh && cd ../.. + +# Push the new certs into the cluster +bash k8s/scripts/create-cert-secrets.sh +``` + +Cert files (`.pfx`, `.crt`, `.key`) are gitignored and never committed. + +### Production-Grade Features + +| Feature | Detail | +|---|---| +| **RBAC** | One `ServiceAccount` per service; least-privilege `Role` scoped to the namespace | +| **NetworkPolicy** | Default deny-all; explicit allow rules between each producer and consumer | +| **PodDisruptionBudget** | `minAvailable: 1` on all stateful services and the API Gateway | +| **HorizontalPodAutoscaler** | CPU-based autoscaling on catalog, basket, order-command, order-query, and api-gateway | +| **Init containers** | Each microservice waits for its database to be ready before starting | +| **Rolling updates** | `maxSurge: 1, maxUnavailable: 0`; zero-downtime deploys | +| **Grafana provisioning** | Prometheus, Loki, and Jaeger datasources provisioned automatically via ConfigMap; no manual setup | +| **Secrets** | All credentials (DB passwords, RabbitMQ, cert PFX password) in Kubernetes Secrets; non-sensitive config in ConfigMaps | + +--- + ## Design Patterns ### CQRS (Command Query Responsibility Segregation) @@ -225,21 +336,21 @@ Commands (writes) and queries (reads) are handled by separate classes using Medi Applied in the Ordering service. `Order` is an aggregate root that enforces business invariants. `OrderItem` is an entity within the aggregate. `Address` and `Money` are value objects with no identity. ### Vertical Slice Architecture -Applied in the Catalog service. Each feature is a self-contained slice — endpoint, command/query, handler, and validator live together in one folder. No horizontal layering by type. +Applied in the Catalog service. Each feature is a self-contained slice; endpoint, command/query, handler, and validator live together in one folder. No horizontal layering by type. ### Outbox Pattern & At-Least-Once Delivery -In a distributed system, publishing a message to a broker and saving data to a database are two separate operations — and either one can fail independently. Without a safety mechanism, this creates a window where your database is updated but the message is never sent (or vice versa), leaving the system in an inconsistent state. +In a distributed system, publishing a message to a broker and saving data to a database are two separate operations; and either one can fail independently. Without a safety mechanism, this creates a window where your database is updated but the message is never sent (or vice versa), leaving the system in an inconsistent state. -The **Outbox pattern** solves this by treating message publishing as part of the same database transaction as the business operation. Instead of publishing directly to RabbitMQ, the service first writes the message to an `Outbox` table in its own database within the same transaction. A background process then reads from the Outbox and reliably forwards messages to the broker. If publishing fails, the background process retries — the message stays in the Outbox until delivery is confirmed. +The **Outbox pattern** solves this by treating message publishing as part of the same database transaction as the business operation. Instead of publishing directly to RabbitMQ, the service first writes the message to an `Outbox` table in its own database within the same transaction. A background process then reads from the Outbox and reliably forwards messages to the broker. If publishing fails, the background process retries; the message stays in the Outbox until delivery is confirmed. -**At-least-once delivery** is the guarantee that a message will be delivered a minimum of one time, but may be delivered more than once in failure scenarios (e.g. the consumer crashes after processing but before acknowledging the message). This is a deliberate trade-off — guaranteeing exactly-once delivery across a distributed system is extremely expensive, whereas at-least-once is achievable with straightforward retries. +**At-least-once delivery** is the guarantee that a message will be delivered a minimum of one time, but may be delivered more than once in failure scenarios (e.g. the consumer crashes after processing but before acknowledging the message). This is a deliberate trade-off; guaranteeing exactly-once delivery across a distributed system is extremely expensive, whereas at-least-once is achievable with straightforward retries. In EshopMicroservices this is implemented via **MassTransit**, which provides: - **Retry policies:** Failed message deliveries are automatically retried with configurable backoff intervals before being considered dead - **Dead-letter queue (DLQ):** Messages that exhaust all retries are moved to a DLQ in RabbitMQ for manual inspection and replay, ensuring no message is silently lost -- **Idempotent consumers:** Because a message may arrive more than once, all consumers are written to be idempotent — processing the same `BasketCheckout` event twice produces the same result as processing it once (typically by checking whether an order with that ID already exists before creating a new one) +- **Idempotent consumers:** Because a message may arrive more than once, all consumers are written to be idempotent; processing the same `BasketCheckout` event twice produces the same result as processing it once (typically by checking whether an order with that ID already exists before creating a new one) **Benefits of this approach:** @@ -317,7 +428,7 @@ you can run the E2E tests with the following command: cd src docker compose -f docker-compose.yml -f docker-compose.e2e.yml up --build -d ``` -4. Wait for services to be ready (optional — alternatively just wait ~60s) +4. Wait for services to be ready (or just alternatively just wait ~60s) ```bash bash scripts/wait-for-services.sh ``` diff --git a/docs/k8s-guide.md b/docs/k8s-guide.md new file mode 100644 index 0000000..e900638 --- /dev/null +++ b/docs/k8s-guide.md @@ -0,0 +1,829 @@ +# EshopMicroservices — Kubernetes Guide + +> I thought its a good idea to write a little bit about the k8s setup for this project. I try to explain the rationale behind the structure and configuration choices, so it can be a reference for anyone looking to deploy a similar stack on Kubernetes. + +--- + +## Table of Contents + +1. [Why Kubernetes?](#1-why-kubernetes) +2. [What We Are Deploying](#2-what-we-are-deploying) +3. [Directory Structure](#3-directory-structure) +4. [Core Infrastructure (00-core)](#4-core-infrastructure-00-core) + - Namespace + - RBAC — ServiceAccounts, Roles, RoleBindings + - Secrets vs ConfigMaps + - Certificate Management +5. [Databases (01-databases)](#5-databases-01-databases) + - StatefulSet vs Deployment + - Why Two Services Per Database? + - PersistentVolumeClaims +6. [Observability Stack (02-observability)](#6-observability-stack-02-observability) +7. [Mail — Mailpit (03-mail)](#7-mail--mailpit-03-mail) +8. [Microservices (04-services)](#8-microservices-04-services) + - Deployment anatomy + - Init containers + - Health probes + - Resource requests and limits + - Discount gRPC — two protocols, two ports + - HorizontalPodAutoscaler + - NetworkPolicy + - PodDisruptionBudget +9. [Ingress (05-ingress)](#9-ingress-05-ingress) +10. [Kustomize — Base & Overlays](#10-kustomize--base--overlays) +11. [Helper Scripts](#11-helper-scripts) +12. [Day-to-Day Workflow](#12-day-to-day-workflow) + +--- + +## 1. Why Kubernetes? + +Docker Compose is great for running the stack locally on a single machine. Kubernetes takes over when you need resilience, scalability, and a path to production. + +| Problem | Docker Compose | Kubernetes | +|---|----------------------------------------|---| +| A container crashes | Stays down until you restart it | Automatically restarted by kubelet | +| High traffic on catalog-api | Manual, restart with more containers | HPA scales replicas based on CPU automatically | +| Deploy a new version with zero downtime | Brief downtime during replace | Rolling update: new pod up before old one stops | +| Drain a node for maintenance | N/A | PodDisruptionBudget guarantees at least 1 pod stays alive | +| Isolate credentials from config | Single .env file mixed with all config | Secrets and ConfigMaps are distinct, RBAC-controlled resources | +| Restrict network traffic | All containers on same bridge network | NetworkPolicy enforces allow-list between pods | + +> **Key Takeaway:** Kubernetes is not just a "fancier Docker Compose". It is a control plane that continuously reconciles your declared desired state with the actual running state of your system. + +--- + +## 2. What We Are Deploying + +The full EshopMicroservices stack running in Kubernetes consists of **148 resources** across these categories: + +| Category | Components | Count | +|---|---|---| +| Microservices | catalog-api, basket-api, discount-grpc, identity-api, order-command-api, order-query-api, order-query-eventprocessor, api-gateway | 8 Deployments | +| Databases | catalog-db, basket-db, identity-db, order-command-db, order-query-db (PostgreSQL 16), Redis, RabbitMQ | 7 StatefulSets | +| Observability | Elasticsearch, Kibana, OTEL Collector, Jaeger, Prometheus, Loki, Grafana | 1 StatefulSet + 6 Deployments | +| Mail | Mailpit (SMTP testing) | 1 Deployment | +| Networking | nginx Ingress rules exposing 7 external hosts | 7 Ingress resources | +| Security | ServiceAccounts, Roles, RoleBindings, NetworkPolicies | 10 + 2 + 9 + 20 | + +``` + ┌──────────────────────────────┐ + │ Browser / API Client │ + └──────────────┬───────────────┘ + │ HTTP *.eshop.local + ┌───────────────────▼───────────────────────┐ + │ nginx Ingress Controller │ + │ api · identity · grafana · kibana · ... │ + └──────────────┬────────────────────────────┘ + │ HTTPS (port 8081) + ┌──────────────▼────────────────────────────┐ + │ API Gateway (YARP) │ + └──┬────────┬──────────┬────────┬───────────┘ + │ │ │ │ + catalog-api basket-api order-* identity-api + │ │ ──gRPC──▶discount-grpc + catalog-db basket-db + redis rabbitmq → order-query-eventprocessor + │ + order-query-db +``` + +--- + +## 3. Directory Structure + +The entire k8s configuration lives in the `k8s/` folder at the repo root. It follows a layered structure: base resources first, then environment-specific overlays on top. + +``` +k8s/ +├── base/ # Canonical resource definitions +│ ├── 00-core/ # Namespace, RBAC, Secrets, ConfigMaps +│ │ ├── namespace.yaml +│ │ ├── rbac.yaml +│ │ ├── configmaps/ # One ConfigMap per service +│ │ ├── secrets/ # DB passwords, certs, RabbitMQ creds +│ │ ├── certs/ # PFX files auto-copied by generate-certs.sh +│ │ └── kustomization.yaml +│ ├── 01-databases/ # PostgreSQL ×5, Redis, RabbitMQ +│ │ ├── catalog-db/ # statefulset.yaml + service.yaml +│ │ ├── basket-db/ +│ │ ├── identity-db/ +│ │ ├── order-command-db/ +│ │ ├── order-query-db/ +│ │ ├── redis/ +│ │ ├── rabbitmq/ +│ │ └── kustomization.yaml +│ ├── 02-observability/ # Full observability stack +│ │ ├── elasticsearch/ +│ │ ├── kibana/ +│ │ ├── otel-collector/ +│ │ ├── jaeger/ +│ │ ├── prometheus/ +│ │ ├── loki/ +│ │ ├── grafana/ +│ │ └── kustomization.yaml +│ ├── 03-mail/ # Mailpit +│ ├── 04-services/ # Microservice Deployments, HPAs, Policies +│ │ ├── catalog-api/ # deployment.yaml · service.yaml · hpa.yaml +│ │ ├── basket-api/ +│ │ ├── discount-grpc/ +│ │ ├── identity-api/ +│ │ ├── order-command-api/ +│ │ ├── order-query-api/ +│ │ ├── order-query-eventprocessor/ +│ │ ├── api-gateway/ +│ │ ├── network-policies.yaml +│ │ ├── pod-disruption-budgets.yaml +│ │ └── kustomization.yaml +│ ├── 05-ingress/ # nginx Ingress rules for *.eshop.local +│ └── kustomization.yaml # Root — references 00-05 in order +├── overlays/ +│ ├── local/ # minikube / Docker Desktop / OrbStack +│ │ ├── kustomization.yaml +│ │ └── patches/ +│ │ ├── resource-limits-patch.yaml # Lighter Elasticsearch for dev +│ │ ├── storage-class-patch.yaml +│ │ └── single-replica-patch.yaml +│ └── production/ # Placeholder for cloud deployments +└── scripts/ + ├── apply.sh # Deploy the full stack + ├── teardown.sh # Remove the stack (optionally wipe data) + ├── create-cert-secrets.sh # Load PFX certs into K8s Secrets + └── hosts-setup.sh # Print /etc/hosts entries for ingress +``` + +> **Why numbered directories?** The numbers (00, 01, 02…) express deployment order. Core resources (namespace, RBAC, secrets) must exist before databases, which must exist before the services that depend on them. Kustomize applies them in the order listed in `kustomization.yaml`. + +> **production?** this is a placeholder for future cloud-specific configuration (e.g. GKE with Cloud SQL, EKS with RDS, AKS with Azure Database). The base configuration is designed to be cloud-agnostic, so the production overlay may be minimal. I didn't want to test it with actual cloud providers during development, so I focused on a local setup that works on any machine with Docker Desktop. +--- + +## 4. Core Infrastructure (00-core) + +### 4.1 Namespace + +A Kubernetes **namespace** is a logical isolation boundary. Everything in this project lives in one namespace: `eshop-microservices`. + +```yaml +apiVersion: v1 +kind: Namespace +metadata: + name: eshop-microservices +``` + +**Why a [namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/)?** +- Isolates all resources from other workloads on the cluster +- [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) rules can be scoped to this namespace only; no accidental access to other namespaces +- Easy to nuke everything: `kubectl delete namespace eshop-microservices` +- Resource quotas can be applied per-namespace in production. for example, you can limit how much cluster resources a particular namespace is allowed to consume. + +A small [ResourceQuota](https://kubernetes.io/docs/concepts/policy/resource-quotas/) example for the `eshop-microservices` namespace: +``` +apiVersion: v1 +kind: ResourceQuota +metadata: + name: frontend-quota + namespace: eshop-microservices +spec: + hard: + pods: "10" + requests.cpu: "4" + requests.memory: 8Gi + limits.cpu: "8" + limits.memory: 16Gi +``` + +--- + +### 4.2 RBAC — ServiceAccounts, Roles, RoleBindings + +**RBAC** (Role-Based Access Control) controls what each pod is allowed to *do* inside the cluster; specifically what Kubernetes API calls it can make. By default, pods run as the `default` service account which has broad permissions. We give each service its own minimal-permission identity. + +``` +ServiceAccount (sa-catalog-api) + │ + └── RoleBinding (rb-catalog-api) + │ + └── Role (role-app-readonly) + rules: + - get on configmaps + - get on secrets +``` + +#### The three RBAC objects + +| Object | What it is | Analogy | +|---|---|---| +| `ServiceAccount` | An identity assigned to pods | A user account | +| `RoleBinding` | Assigns a Role to a ServiceAccount | Giving someone that job title | +| `Role` | A named set of permissions within a namespace | A job title with defined permissions | + +#### What we created + +- **10 ServiceAccounts** — one per service group (`sa-databases`, `sa-observability`) and one per microservice +- **2 Roles**: + - `role-app-readonly` — microservices can `get` their ConfigMap and Secret + - `role-observability` — Prometheus can `get/list/watch` Pods and Endpoints for service discovery +- **9 RoleBindings** — each microservice SA bound to `role-app-readonly` + +> **Principle of Least Privilege:** No ServiceAccount has `create`, `update`, or `delete` permissions. No ClusterRole is granted; permissions are namespace-scoped only. If a pod is compromised, the blast radius is limited. + +--- + +### 4.3 [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) vs [ConfigMaps](https://kubernetes.io/docs/concepts/configuration/configmap/) + +Both are key-value stores that inject configuration into pods. The difference is sensitivity: + +| | ConfigMap | Secret | +|---|---|---| +| Stores | Non-sensitive config (URLs, ports, feature flags) | Passwords, tokens, certificates | +| Stored as | Plain text | Base64-encoded | +| Example | `OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317` | `POSTGRES_PASSWORD=cG9zdGdyZXM=` | + +#### How a microservice gets its config + +```yaml +# 1. Non-sensitive config injected from ConfigMap +envFrom: + - configMapRef: + name: catalog-api-cm + +# 2. Sensitive values injected from Secrets +env: + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: catalog-db-secret + key: POSTGRES_PASSWORD + +# 3. Connection string assembled using K8s env-var interpolation + - name: ConnectionStrings__Database + value: "Server=catalog-db;Port=5432;Database=CatalogDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" +``` + +> **Why not put the full connection string in a Secret?** The host, port, and database name are not sensitive; they are the same in every environment. Only the password changes. Keeping them in a ConfigMap makes it easy to see the topology without managing secrets unnecessarily. + +--- + +### 4.4 Certificate Management + +Each ASP.NET Core service uses Kestrel's built-in HTTPS with a PFX certificate. In Kubernetes, certificates live as **Secrets**. + +#### The certificate flow + +``` +1. src/certificates/generate-certs.sh + ↓ generates CA + 8 PFX files + ↓ auto-copies to k8s/base/00-core/certs/ + +2. k8s/scripts/create-cert-secrets.sh + ↓ reads each .pfx + ↓ creates Kubernetes Secret: cert-catalog-api, cert-basket-api, ... + ↓ creates ConfigMap: cert-ca (the public CA certificate) + +3. Each Deployment mounts a projected volume: + /app/certificates/catalog.pfx ← from Secret + /app/certificates/ca.crt ← from ConfigMap +``` + +```yaml +# Projected volume in every microservice Deployment +volumes: + - name: certs + projected: + sources: + - secret: + name: cert-catalog-api # private PFX + - configMap: + name: cert-ca # public CA cert for trust chain +``` + +> **Projected volumes** merge multiple sources (secrets, configmaps) into a single directory mount. This is why both the PFX and the CA cert appear in the same `/app/certificates/` folder inside the container. + +--- + +## 5. Databases (01-databases) + +### 5.1 [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) vs [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) + +Databases have state; they write data to disk. Kubernetes provides two workload types: + +| | Deployment | StatefulSet | +|---|---|---| +| Pod naming | Random suffix: `catalog-api-6f9b-xkp2z` | Ordered, stable: `catalog-db-0`, `catalog-db-1` | +| Storage | Shared or ephemeral | Each pod gets its own dedicated PVC | +| Startup/shutdown | All pods start/stop simultaneously | Ordered: 0 before 1, 1 before 2 | +| Use for | Stateless services (APIs, proxies) | Stateful services (databases, queues) | + +All 7 data stores (5× PostgreSQL, Redis, RabbitMQ) are StatefulSets. Elasticsearch is also a StatefulSet. + +--- + +### 5.2 Why Two Services Per Database? + +Every database StatefulSet has **two Kubernetes Services**. This is a standard Kubernetes pattern: + +``` +catalog-db-0 (pod) + │ + ├── catalog-db-headless (clusterIP: None) + │ DNS: catalog-db-0.catalog-db-headless.eshop-microservices.svc.cluster.local + │ Used by: StatefulSet controller (required) + │ Behaviour: Returns the pod IP directly. No load balancing. + │ + └── catalog-db (ClusterIP) + DNS: catalog-db (short form within namespace) + Used by: catalog-api connection string + Behaviour: Load-balanced → routes to ready pod +``` +K8s uses headless DNS internally for pod identity, ordered startup, and PVC binding. This happens whether or not any app ever uses these DNS names. It's not optional. + +| Service | clusterIP | Who uses it | Why | +|---|---|---|---| +| `catalog-db-headless` | `None` | K8s StatefulSet controller | Gives each pod a stable unique DNS name. Required by `spec.serviceName`. | +| `catalog-db` | Assigned by K8s | `catalog-api` connection string | Stable address for apps. Handles pod failover transparently. | + +> **When does the headless service become critical?** With a single replica the headless service isn’t technically necessary. But if you scaled to 2 replicas with PostgreSQL streaming replication, the primary would be at `catalog-db-0.catalog-db-headless` and the replica at `catalog-db-1.catalog-db-headless`; and the application (if necessary) could choose which to connect to. + +--- + +### 5.3 [PersistentVolumeClaims](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) + +StatefulSets use `volumeClaimTemplates`; a template that automatically creates one PVC per pod: + +```yaml +volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] # Only one pod can mount this at a time + storageClassName: local-path # Patched per environment by overlay + resources: + requests: + storage: 1Gi +``` + +| Term | Meaning | +|---|---| +| `PersistentVolume (PV)` | Actual storage provisioned on the cluster (a disk) | +| `PersistentVolumeClaim (PVC)` | A request for storage by a pod. K8s binds PVC → PV automatically. | +| `StorageClass` | Defines how storage is provisioned. `local-path` (OrbStack/minikube), `pd-ssd` (GKE), `gp3` (EKS). | +| `ReadWriteOnce` | Only one node can mount this volume at a time. Fine for single-replica databases. | + +> **PVCs survive StatefulSet deletion.** When you run `kubectl delete -k k8s/overlays/local`, all StatefulSets are deleted but their PVCs remain. Your data is preserved across redeployments. Add `kubectl delete pvc --all -n eshop-microservices` only when you want a clean slate. + +Note: Use volumeClaimTemplates in StatefulSets when each replica needs its own isolated storage (databases). Use a standalone PVC + Deployment when you have a single-replica workload that just needs persistent storage (Prometheus, Loki, Mailpit). if you deployment has more than one replica you need to use ReadWriteMany mode. ReadWriteOnce mode allow only one replica to mount. + +--- + +## 6. Observability Stack (02-observability) + +The observability stack provides three pillars: **metrics**, **logs**, and **traces**. + +``` +Microservice + │ + └── OpenTelemetry SDK (in every .NET service) + │ + ▼ OTLP (gRPC port 4317) + otel-collector + │ + ├── Traces ──────────────▶ Jaeger (jaeger.eshop.local) + ├── Metrics (Prometheus) ▶ Prometheus (prometheus.eshop.local) + │ └──▶ Grafana (grafana.eshop.local) + └── Logs ────────────────▶ Loki + └──▶ Grafana + +Microservices also send structured logs to Elasticsearch: + └──▶ Elasticsearch ──▶ Kibana (kibana.eshop.local) +``` + +| Component | Role | Storage | +|---|---|---| +| OTEL Collector | Central telemetry aggregator — receives from all services, fans out to backends | Stateless | +| Jaeger | Distributed tracing UI — shows end-to-end request flows across services | In-memory (stateless) | +| Prometheus | Time-series metrics database — scrapes all service /metrics endpoints | PVC 1Gi | +| Loki | Log aggregation — stores structured logs from OTEL Collector | PVC 1Gi | +| Grafana | Dashboard UI — pre-provisioned with Prometheus, Loki, and Jaeger datasources | Stateless | +| Elasticsearch | Full-text log search engine — receives logs from Serilog in each service | StatefulSet, PVC 2Gi | +| Kibana | Elasticsearch UI — log search and dashboards | Stateless | + +#### Why Grafana is stateless + +Grafana's datasources and dashboards are *provisioned via a ConfigMap* at startup. Nothing is stored inside the container itself, so it needs no PVC. Delete and recreate it freely without losing any configuration. + +```yaml +# grafana/provisioning-cm.yaml — auto-loads datasources on startup +data: + datasources.yaml: | + datasources: + - name: Prometheus + type: prometheus + url: http://prometheus:9090 + isDefault: true + - name: Loki + type: loki + url: http://loki:3100 + - name: Jaeger + type: jaeger + url: http://jaeger:16686 +``` + +--- + +## 7. Mail — Mailpit (03-mail) + +Mailpit is a local SMTP server and web UI for catching emails during development. The Identity service sends verification emails — Mailpit traps them so they never reach real inboxes. + +| Port | Purpose | Access | +|---|---|---| +| 1025 | SMTP — receives emails from identity-api | Internal only | +| 8025 | Web UI — browse captured emails | `http://mailpit.eshop.local` | + +--- + +## 8. Microservices (04-services) + +### 8.1 Anatomy of a Microservice Deployment + +Every microservice follows the same pattern. Annotated Deployment for catalog-api: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: catalog-api + namespace: eshop-microservices +spec: + replicas: 1 # HPA will scale this automatically + selector: + matchLabels: + app: catalog-api + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 # Spin up 1 new pod before removing old one + maxUnavailable: 0 # This is for zero downtime: never kill pod until new is ready + template: + spec: + serviceAccountName: sa-catalog-api # Least-privilege identity + initContainers: # Wait for DB before starting + - name: wait-for-db + image: busybox:1.36 + command: [ 'sh', '-c', 'until nc -z catalog-db 5432; do sleep 2; done' ] + containers: + - name: catalog-api + envFrom: # All non-sensitive config from ConfigMap + - configMapRef: + name: catalog-api-cm + env: # Sensitive values from Secrets + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: catalog-db-secret + key: POSTGRES_PASSWORD + livenessProbe: # K8s restarts pod if this fails + httpGet: { path: /hc, port: 8080 } + readinessProbe: # K8s stops routing traffic if this fails + httpGet: { path: /hc, port: 8080 } + resources: + requests: { cpu: 100m, memory: 128Mi } + limits: { cpu: 500m, memory: 512Mi } + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true +``` + +--- + +### 8.2 Init Containers + +An **init container** runs to completion before the main container starts. We use them to make each microservice wait until its database is accepting connections: + +```yaml +initContainers: + - name: wait-for-db + image: busybox:1.36 + command: + - sh + - -c + - 'until nc -z catalog-db 5432; do echo waiting for catalog-db; sleep 2; done' +``` + +Without this, the service would start, fail to connect to the database, crash, and restart repeatedly (CrashLoopBackOff). Init containers solve the startup ordering problem elegantly. + +> **Why not use `depends_on` like Docker Compose?** Kubernetes has no native equivalent of `depends_on`. Init containers are the idiomatic solution. + +--- + +### 8.3 Health Probes + +Every service exposes a `/hc` endpoint via ASP.NET Core Health Checks. Kubernetes uses two probe types: + +| Probe | What it does | On failure | +|---|---|---| +| **livenessProbe** | Is the process alive? Checks if it is stuck or deadlocked. | Pod is killed and restarted | +| **readinessProbe** | Is the pod ready to receive traffic? Checks if dependencies are healthy. | Pod removed from Service endpoints (no traffic sent) | + +Both probes use `GET /hc port 8080`. The key difference: **liveness restarts the pod; readiness just stops traffic to it.** + +--- + +### 8.4 Resource Requests and Limits + +```yaml +resources: + requests: { cpu: 100m, memory: 128Mi } # Guaranteed minimum + limits: { cpu: 500m, memory: 512Mi } # Hard maximum +``` + +| Term | Meaning | +|---|---| +| `100m` CPU | 100 millicores = 0.1 of one CPU core | +| `requests` | K8s scheduler uses this to decide which node can fit the pod. The pod is guaranteed at least this much. | +| `limits` | Pod is killed (OOMKilled) if it exceeds memory limit. CPU is throttled at the limit. | + +--- + +### 8.5 Discount gRPC — Two Protocols, Two Ports + +The Discount service speaks **gRPC** (not HTTP), and needs two ports because two different callers use it differently: + +``` +basket-api ──gRPC plaintext (h2c)──▶ discount-grpc:8080 +api-gateway ──HTTPS (YARP proxy)──▶ discount-grpc:8081 +``` + +```yaml +# Service exposes both protocols +ports: + - port: 8080 + name: grpc + appProtocol: kubernetes.io/h2c # HTTP/2 cleartext — required for gRPC + - port: 8081 + name: https +``` + +Liveness/readiness probes use the native Kubernetes gRPC probe type (K8s 1.24+): + +```yaml +livenessProbe: + grpc: + port: 8080 # gRPC health protocol on the plaintext port +``` + +--- + +### 8.6 [HorizontalPodAutoscaler](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/) + +An HPA automatically adjusts the number of pod replicas based on CPU usage: + +```yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +spec: + scaleTargetRef: + kind: Deployment + name: catalog-api + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 # Scale up when avg CPU > 70% +``` + +HPAs are applied to: `catalog-api` (max 5), `basket-api` (max 5), `order-command-api` (max 3), `order-query-api` (max 3), `api-gateway` (max 3). + +**Not applied to:** `discount-grpc` (low-traffic internal), `order-query-eventprocessor` (must have exactly one consumer per queue). + +--- + +### 8.7 [NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) + +By default, all pods in a namespace can talk to each other freely. NetworkPolicy changes this to an allow-list model. + +We start with a **deny-all** default and add explicit allow rules: + +```yaml +# Step 1: Deny everything +kind: NetworkPolicy +metadata: + name: default-deny-ingress +spec: + podSelector: {} # Applies to ALL pods in namespace + policyTypes: [Ingress] + +# Step 2: Allow only what is documented +kind: NetworkPolicy +metadata: + name: netpol-catalog-api +spec: + podSelector: + matchLabels: { app: catalog-api } + egress: + - to: [{ podSelector: { matchLabels: { app: catalog-db }}}] + ports: [{ port: 5432 }] + - to: [{ podSelector: { matchLabels: { app: otel-collector }}}] + ports: [{ port: 4317 }] +``` + +> **NetworkPolicy requires a CNI plugin that supports it.** Docker Desktop and OrbStack's default CNI does not enforce NetworkPolicy. In production (GKE, EKS, AKS), network policies are enforced by default. + +--- + +### 8.8 [PodDisruptionBudget](https://kubernetes.io/docs/reference/kubernetes-api/policy/pod-disruption-budget-v1/) + +A PDB prevents Kubernetes from evicting too many pods at once during planned maintenance (e.g. node drain for an OS upgrade): + +```yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +spec: + minAvailable: 1 # At least 1 pod must stay running during disruption + selector: + matchLabels: { app: catalog-api } +``` + +With `minAvailable: 1` and a single replica, a node drain will *wait* until the pod is rescheduled elsewhere before proceeding. Especially important for database nodes in production. + +--- + +## 9. [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) (05-ingress) + +The **Ingress** resource is a layer-7 HTTP router sitting in front of all services and routing requests based on hostname. + +``` +Browser: GET http://kibana.eshop.local + │ + ▼ +/etc/hosts: kibana.eshop.local → 198.19.249.2 + │ + ▼ +nginx Ingress Controller (LoadBalancer on port 80) + │ + ├── Host: api.eshop.local ──▶ api-gateway:8081 (HTTPS backend) + ├── Host: identity.eshop.local ──▶ identity-api:8081 (HTTPS backend) + ├── Host: kibana.eshop.local ──▶ kibana:5601 (HTTP backend) + ├── Host: grafana.eshop.local ──▶ grafana:3000 (HTTP backend) + ├── Host: jaeger.eshop.local ──▶ jaeger:16686 (HTTP backend) + ├── Host: prometheus.eshop.local ──▶ prometheus:9090 (HTTP backend) + └── Host: mailpit.eshop.local ──▶ mailpit:8025 (HTTP backend) +``` + +#### HTTPS backends + +The API Gateway and Identity API terminate TLS themselves using Kestrel. nginx needs to be told to connect to them over HTTPS: + +```yaml +metadata: + annotations: + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/proxy-ssl-verify: "false" # Self-signed CA +``` + +The other services (Kibana, Grafana, etc.) are plain HTTP; no annotation needed. + +--- + +## 10. Kustomize — Base & Overlays + +Kustomize solves a real problem: you want the same application running in different environments with slightly different configuration, but you don't want to duplicate 88 YAML files. + +### 10.1 Why Kustomize instead of Helm? + +| | Kustomize | Helm | +|---|---|---| +| Templating | No templating — patch existing YAML | Go template language in all YAML files | +| Built into kubectl | Yes — `kubectl apply -k` | No — requires separate installation | +| Learning curve | Low — you just write plain YAML | Higher — template syntax, values.yaml, chart structure | +| Base resources | Always valid YAML, readable at a glance | Filled with `{{ .Values.something }}` | +| Best for | Small/medium projects, plain YAML fans | Complex packages shared across many teams | + +### 10.2 The base kustomization + +```yaml +# k8s/base/kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - 00-core # Applied first — namespace must exist before everything else + - 01-databases # Applied second — databases before services that depend on them + - 02-observability + - 03-mail + - 04-services + - 05-ingress +``` + +### 10.3 The local overlay + +```yaml +# k8s/overlays/local/kustomization.yaml +resources: + - ../../base + +patches: + # Patch 1: Change storageClass to local-path for all StatefulSets + - patch: |- + - op: replace + path: /spec/volumeClaimTemplates/0/spec/storageClassName + value: local-path + target: { kind: StatefulSet } + + # Patch 2: Change storageClass to local-path for standalone PVCs + - patch: |- + - op: replace + path: /spec/storageClassName + value: local-path + target: { kind: PersistentVolumeClaim } + + # Patch 3: Reduce Elasticsearch memory for local dev machines + - path: patches/resource-limits-patch.yaml + target: { kind: StatefulSet, name: elasticsearch } + +images: # Override image tags per environment + - name: catalog.api + newName: catalog.api + newTag: latest +``` + +> **The power of Kustomize patches:** The two inline JSON patches (`op: replace`) change the storage class for *all* StatefulSets and PVCs in a single declaration. Without Kustomize, you would have to edit 10+ files. + +--- + +## 11. Helper Scripts + +| Script | What it does | When to run | +|---|---|---| +| `generate-certs.sh` | Creates CA + 8 PFX certificates with K8s DNS SANs, auto-copies to `k8s/base/00-core/certs/` | Once (re-run when certs expire after 365 days) | +| `create-cert-secrets.sh` | Reads PFX files and creates Kubernetes Secrets + `cert-ca` ConfigMap | After generate-certs.sh, or after a full cluster reset | +| `apply.sh` | Checks cluster, runs cert script if secrets are missing, then `kubectl apply -k overlays/local` | Every deploy | +| `teardown.sh` | Runs `kubectl delete -k overlays/local`. With `--wipe-data` also deletes all PVCs. | When removing the stack | +| `hosts-setup.sh` | Detects the ingress LoadBalancer IP, prints 7 `/etc/hosts` entries | Once per machine (after first deploy) | + +--- + +## 12. Day-to-Day Workflow + +### First-time setup + +```bash +# 1. Enable Kubernetes in Docker Desktop, then install nginx ingress controller +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/cloud/deploy.yaml + +# 2. Build images +cd src && docker compose build && cd .. + +# 3. Generate certs (writes to k8s/base/00-core/certs/ automatically) +mkdir -p k8s/base/00-core/certs +cd src/certificates && bash generate-certs.sh && cd ../.. + +# 4. Deploy +bash k8s/scripts/apply.sh local + +# 5. Set up /etc/hosts (once per machine) +# The IP is stable across eshop redeployments — only redo this after a full cluster reset. +bash k8s/scripts/hosts-setup.sh | sudo tee -a /etc/hosts +``` + +### Daily workflow + +```bash +# After changing code, rebuild and redeploy: +cd src && docker compose build && cd .. +bash k8s/scripts/apply.sh local + +# Tear down (data preserved in PVCs): +bash k8s/scripts/teardown.sh local + +# Tear down + wipe all data: +bash k8s/scripts/teardown.sh local --wipe-data + +# Watch pod status: +kubectl get pods -n eshop-microservices -w + +# See logs for a service: +kubectl logs -n eshop-microservices -l app=catalog-api --follow + +# Describe a crashing pod: +kubectl describe pod -n eshop-microservices +``` + +### URLs after deployment + +| URL | What you see | +|---|---| +| `http://api.eshop.local` | API Gateway — entry point for all API calls | +| `http://identity.eshop.local` | Identity Server — OIDC login / token endpoints | +| `http://grafana.eshop.local` | Grafana — metrics + logs dashboards (anonymous admin) | +| `http://kibana.eshop.local` | Kibana — Elasticsearch log search UI | +| `http://jaeger.eshop.local` | Jaeger — distributed trace explorer | +| `http://prometheus.eshop.local` | Prometheus — raw metrics query UI | +| `http://mailpit.eshop.local` | Mailpit — captured emails from Identity service | + +--- + +*EshopMicroservices Kubernetes Guide — Behdad Kardgar* diff --git a/k8s/base/00-core/certs/.gitkeep b/k8s/base/00-core/certs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/k8s/base/00-core/configmaps/api-gateway-cm.yaml b/k8s/base/00-core/configmaps/api-gateway-cm.yaml new file mode 100644 index 0000000..13d29f1 --- /dev/null +++ b/k8s/base/00-core/configmaps/api-gateway-cm.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: api-gateway-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/api-gateway.pfx" + Certificates__CaPath: "/app/certificates/ca.crt" + ReverseProxy__Clusters__catalog__Destinations__destination0__Address: "https://catalog-api:8081" + ReverseProxy__Clusters__basket__Destinations__destination0__Address: "https://basket-api:8081" + ReverseProxy__Clusters__discount__Destinations__destination0__Address: "https://discount-grpc:8081" + ReverseProxy__Clusters__order-command__Destinations__destination0__Address: "https://order-command-api:8081" + ReverseProxy__Clusters__order-query__Destinations__destination0__Address: "https://order-query-api:8081" + ReverseProxy__Clusters__identity__Destinations__destination0__Address: "https://identity-api:8081" + Logger__elasticsearch: "http://elasticsearch:9200" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/basket-api-cm.yaml b/k8s/base/00-core/configmaps/basket-api-cm.yaml new file mode 100644 index 0000000..40c0e66 --- /dev/null +++ b/k8s/base/00-core/configmaps/basket-api-cm.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: basket-api-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/basket.pfx" + ConnectionStrings__Redis: "redis:6379" + Grpc__Discount: "http://discount-grpc:8080" + OrderCommandClient__BaseUrl: "http://order-command-api:8080" + Logger__elasticsearch: "http://elasticsearch:9200" + Identity__Url: "https://identity.eshop.local" + Identity__Audience: "basket" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/catalog-api-cm.yaml b/k8s/base/00-core/configmaps/catalog-api-cm.yaml new file mode 100644 index 0000000..c4ec749 --- /dev/null +++ b/k8s/base/00-core/configmaps/catalog-api-cm.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: catalog-api-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/catalog.pfx" + Logger__elasticsearch: "http://elasticsearch:9200" + Identity__Url: "https://identity.eshop.local" + Identity__Audience: "catalog" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/discount-grpc-cm.yaml b/k8s/base/00-core/configmaps/discount-grpc-cm.yaml new file mode 100644 index 0000000..152882e --- /dev/null +++ b/k8s/base/00-core/configmaps/discount-grpc-cm.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: discount-grpc-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/discount.pfx" + ConnectionStrings__Database: "Data Source=/app/data/discountDb" + Logger__elasticsearch: "http://elasticsearch:9200" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/identity-api-cm.yaml b/k8s/base/00-core/configmaps/identity-api-cm.yaml new file mode 100644 index 0000000..4db2a48 --- /dev/null +++ b/k8s/base/00-core/configmaps/identity-api-cm.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: identity-api-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/identity.pfx" + EmailService__base_url: "mailpit" + EmailService__sender: "no-reply@eshop.dev" + service_url: "https://identity-api:8081" + IdentityServer__IssuerUri: "https://identity.eshop.local" + Logger__elasticsearch: "http://elasticsearch:9200" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/jaeger-ui-cm.yaml b/k8s/base/00-core/configmaps/jaeger-ui-cm.yaml new file mode 100644 index 0000000..83563c9 --- /dev/null +++ b/k8s/base/00-core/configmaps/jaeger-ui-cm.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jaeger-ui-config + namespace: eshop-microservices +data: + jaeger-ui.json: | + { + "monitor": { + "menuEnabled": true + }, + "dependencies": { + "menuEnabled": true + } + } + sampling_strategies.json: | + { + "default_strategy": { + "type": "probabilistic", + "param": 1 + } + } diff --git a/k8s/base/00-core/configmaps/loki-config-cm.yaml b/k8s/base/00-core/configmaps/loki-config-cm.yaml new file mode 100644 index 0000000..c379934 --- /dev/null +++ b/k8s/base/00-core/configmaps/loki-config-cm.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: loki-config + namespace: eshop-microservices +data: + loki-config.yml: | + auth_enabled: false + + server: + http_listen_port: 3100 + + ingester: + lifecycler: + address: 127.0.0.1 + ring: + kvstore: + store: inmemory + replication_factor: 1 + final_sleep: 0s + chunk_idle_period: 5m + chunk_retain_period: 30s + wal: + enabled: false + + schema_config: + configs: + - from: 2022-01-01 + store: boltdb + object_store: filesystem + schema: v11 + index: + prefix: index_ + period: 168h + + storage_config: + boltdb: + directory: /tmp/loki/index + filesystem: + directory: /tmp/loki/chunks + + limits_config: + enforce_metric_name: false + reject_old_samples: true + reject_old_samples_max_age: 168h diff --git a/k8s/base/00-core/configmaps/order-command-api-cm.yaml b/k8s/base/00-core/configmaps/order-command-api-cm.yaml new file mode 100644 index 0000000..94f4cea --- /dev/null +++ b/k8s/base/00-core/configmaps/order-command-api-cm.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: order-command-api-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/order-command-api.pfx" + RabbitMQ__URI: "rabbitmq" + Identity__Url: "https://identity.eshop.local" + Identity__Audience: "orders_command" + Logger__elasticsearch: "http://elasticsearch:9200" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/order-query-api-cm.yaml b/k8s/base/00-core/configmaps/order-query-api-cm.yaml new file mode 100644 index 0000000..a5fc65c --- /dev/null +++ b/k8s/base/00-core/configmaps/order-query-api-cm.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: order-query-api-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/order-query-event-api.pfx" + Logger__elasticsearch: "http://elasticsearch:9200" + Identity__Url: "https://identity.eshop.local" + Identity__Audience: "orders_query" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/order-query-eventprocessor-cm.yaml b/k8s/base/00-core/configmaps/order-query-eventprocessor-cm.yaml new file mode 100644 index 0000000..040ddfe --- /dev/null +++ b/k8s/base/00-core/configmaps/order-query-eventprocessor-cm.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: order-query-eventprocessor-cm + namespace: eshop-microservices +data: + ASPNETCORE_ENVIRONMENT: "Development" + ASPNETCORE_HTTP_PORTS: "8080" + ASPNETCORE_HTTPS_PORTS: "8081" + ASPNETCORE_Kestrel__Certificates__Default__Path: "/app/certificates/order-query-event-processor.pfx" + RabbitMQ__URI: "rabbitmq" + QueueSettings__OrderViewQueues__OrderCreatedEvent__Name: "order_created_event_queue" + QueueSettings__OrderViewQueues__OrderCreatedEvent__Dlq: "order_created_event_queue_dlq" + QueueSettings__OrderViewQueues__OrderCreatedEvent__Exchange: "order_created_event_exchange" + QueueSettings__OrderViewQueues__OrderUpdatedEvent__Name: "order_updated_event_queue" + QueueSettings__OrderViewQueues__OrderUpdatedEvent__Dlq: "order_updated_event_queue_dlq" + QueueSettings__OrderViewQueues__OrderUpdatedEvent__Exchange: "order_updated_event_exchange" + QueueSettings__OrderViewQueues__OrderDeletedEvent__Name: "order_deleted_event_queue" + QueueSettings__OrderViewQueues__OrderDeletedEvent__Dlq: "order_deleted_event_queue_dlq" + QueueSettings__OrderViewQueues__OrderDeletedEvent__Exchange: "order_deleted_event_exchange" + Logger__elasticsearch: "http://elasticsearch:9200" + OTEL_EXPORTER_JAEGER_AGENT_HOST: "jaeger" + OTEL_EXPORTER_JAEGER_AGENT_PORT: "6831" + OTEL_EXPORTER_JAEGER_ENDPOINT: "http://jaeger:14268/api/traces" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector:4317" diff --git a/k8s/base/00-core/configmaps/otel-collector-config-cm.yaml b/k8s/base/00-core/configmaps/otel-collector-config-cm.yaml new file mode 100644 index 0000000..8c7df36 --- /dev/null +++ b/k8s/base/00-core/configmaps/otel-collector-config-cm.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: otel-collector-config + namespace: eshop-microservices +data: + otel-collector-config.yml: | + receivers: + otlp: + protocols: + grpc: + http: + + exporters: + prometheus: + endpoint: "0.0.0.0:8889" + + otlp: + endpoint: "jaeger:4317" + tls: + insecure: true + + loki: + endpoint: http://loki:3100/loki/api/v1/push + + connectors: + spanmetrics: + histogram: + explicit: + buckets: [5ms, 10ms, 25ms, 50ms, 100ms, 250ms, 500ms, 1000ms] + + processors: + filter/exclude-health-api-traces: + error_mode: ignore + traces: + span: + - 'attributes["http.route"] == "/health"' + - 'attributes["http.route"] == "/hc"' + filter/exclude-health-api-logs: + error_mode: ignore + logs: + exclude: + match_type: strict + record_attributes: + - key: RequestPath + value: /hc + resource: + attributes: + - action: insert + key: service_name + from_attribute: service.name + - action: insert + key: loki.resource.labels + value: service_name + + service: + pipelines: + traces: + receivers: [otlp] + processors: [filter/exclude-health-api-traces] + exporters: [otlp, spanmetrics] + metrics: + receivers: [spanmetrics] + exporters: [prometheus] + logs: + receivers: [otlp] + processors: [resource, filter/exclude-health-api-logs] + exporters: [loki] diff --git a/k8s/base/00-core/configmaps/prometheus-config-cm.yaml b/k8s/base/00-core/configmaps/prometheus-config-cm.yaml new file mode 100644 index 0000000..cba66af --- /dev/null +++ b/k8s/base/00-core/configmaps/prometheus-config-cm.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + namespace: eshop-microservices +data: + prometheus.yml: | + global: + scrape_interval: 10s + evaluation_interval: 10s + + scrape_configs: + - job_name: aggregated-trace-metrics + static_configs: + - targets: + - otel-collector:8889 + + - job_name: jaeger + static_configs: + - targets: + - jaeger:14269 + + - job_name: services + static_configs: + - targets: + - catalog-api:8080 + - basket-api:8080 + - discount-grpc:8080 + - order-command-api:8080 + - identity-api:8080 + - order-query-eventprocessor:8080 + - order-query-api:8080 diff --git a/k8s/base/00-core/kustomization.yaml b/k8s/base/00-core/kustomization.yaml new file mode 100644 index 0000000..2715f8e --- /dev/null +++ b/k8s/base/00-core/kustomization.yaml @@ -0,0 +1,24 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eshop-microservices + +resources: + - namespace.yaml + - rbac.yaml + - secrets/db-secrets.yaml + - secrets/rabbitmq-secret.yaml + - secrets/identity-secret.yaml + - secrets/cert-password-secret.yaml + - configmaps/otel-collector-config-cm.yaml + - configmaps/prometheus-config-cm.yaml + - configmaps/loki-config-cm.yaml + - configmaps/jaeger-ui-cm.yaml + - configmaps/catalog-api-cm.yaml + - configmaps/basket-api-cm.yaml + - configmaps/discount-grpc-cm.yaml + - configmaps/identity-api-cm.yaml + - configmaps/order-command-api-cm.yaml + - configmaps/order-query-api-cm.yaml + - configmaps/order-query-eventprocessor-cm.yaml + - configmaps/api-gateway-cm.yaml diff --git a/k8s/base/00-core/namespace.yaml b/k8s/base/00-core/namespace.yaml new file mode 100644 index 0000000..520896b --- /dev/null +++ b/k8s/base/00-core/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: eshop-microservices + labels: + app.kubernetes.io/managed-by: kustomize + environment: local diff --git a/k8s/base/00-core/rbac.yaml b/k8s/base/00-core/rbac.yaml new file mode 100644 index 0000000..bd19038 --- /dev/null +++ b/k8s/base/00-core/rbac.yaml @@ -0,0 +1,208 @@ +# ── ServiceAccounts ──────────────────────────────────────────────────────────── +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-databases + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-observability + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-catalog-api + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-basket-api + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-discount-grpc + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-identity-api + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-order-command-api + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-order-query-api + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-order-query-eventprocessor + namespace: eshop-microservices +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sa-api-gateway + namespace: eshop-microservices +--- +# ── Roles ───────────────────────────────────────────────────────────────────── +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: role-observability + namespace: eshop-microservices +rules: + - apiGroups: [""] + resources: ["pods", "endpoints", "services"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: role-app-readonly + namespace: eshop-microservices +rules: + - apiGroups: [""] + resources: ["configmaps", "secrets"] + verbs: ["get"] +--- +# ── RoleBindings ────────────────────────────────────────────────────────────── +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-observability + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-observability +subjects: + - kind: ServiceAccount + name: sa-observability + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-catalog-api + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-catalog-api + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-basket-api + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-basket-api + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-discount-grpc + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-discount-grpc + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-identity-api + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-identity-api + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-order-command-api + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-order-command-api + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-order-query-api + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-order-query-api + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-order-query-eventprocessor + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-order-query-eventprocessor + namespace: eshop-microservices +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rb-api-gateway + namespace: eshop-microservices +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: role-app-readonly +subjects: + - kind: ServiceAccount + name: sa-api-gateway + namespace: eshop-microservices diff --git a/k8s/base/00-core/secrets/cert-password-secret.yaml b/k8s/base/00-core/secrets/cert-password-secret.yaml new file mode 100644 index 0000000..fa35898 --- /dev/null +++ b/k8s/base/00-core/secrets/cert-password-secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: cert-password + namespace: eshop-microservices +type: Opaque +data: + CERT_PASSWORD: ZGV2 diff --git a/k8s/base/00-core/secrets/db-secrets.yaml b/k8s/base/00-core/secrets/db-secrets.yaml new file mode 100644 index 0000000..71b6525 --- /dev/null +++ b/k8s/base/00-core/secrets/db-secrets.yaml @@ -0,0 +1,49 @@ +apiVersion: v1 +kind: Secret +metadata: + name: catalog-db-secret + namespace: eshop-microservices +type: Opaque +data: + POSTGRES_USER: cG9zdGdyZXM= + POSTGRES_PASSWORD: cG9zdGdyZXM= +--- +apiVersion: v1 +kind: Secret +metadata: + name: basket-db-secret + namespace: eshop-microservices +type: Opaque +data: + POSTGRES_USER: cG9zdGdyZXM= + POSTGRES_PASSWORD: cG9zdGdyZXM= +--- +apiVersion: v1 +kind: Secret +metadata: + name: identity-db-secret + namespace: eshop-microservices +type: Opaque +data: + POSTGRES_USER: cG9zdGdyZXM= + POSTGRES_PASSWORD: cG9zdGdyZXM= +--- +apiVersion: v1 +kind: Secret +metadata: + name: order-command-db-secret + namespace: eshop-microservices +type: Opaque +data: + POSTGRES_USER: cG9zdGdyZXM= + POSTGRES_PASSWORD: cG9zdGdyZXM= +--- +apiVersion: v1 +kind: Secret +metadata: + name: order-query-db-secret + namespace: eshop-microservices +type: Opaque +data: + POSTGRES_USER: cG9zdGdyZXM= + POSTGRES_PASSWORD: cG9zdGdyZXM= diff --git a/k8s/base/00-core/secrets/identity-secret.yaml b/k8s/base/00-core/secrets/identity-secret.yaml new file mode 100644 index 0000000..07d3944 --- /dev/null +++ b/k8s/base/00-core/secrets/identity-secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: identity-secret + namespace: eshop-microservices +type: Opaque +data: + EmailService__authentication_key: Y2hhbmdlbWU= diff --git a/k8s/base/00-core/secrets/rabbitmq-secret.yaml b/k8s/base/00-core/secrets/rabbitmq-secret.yaml new file mode 100644 index 0000000..efeb9b5 --- /dev/null +++ b/k8s/base/00-core/secrets/rabbitmq-secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: rabbitmq-secret + namespace: eshop-microservices +type: Opaque +data: + RABBITMQ_USERNAME: Z3Vlc3Q= + RABBITMQ_PASSWORD: Z3Vlc3Q= diff --git a/k8s/base/01-databases/basket-db/service.yaml b/k8s/base/01-databases/basket-db/service.yaml new file mode 100644 index 0000000..492bacf --- /dev/null +++ b/k8s/base/01-databases/basket-db/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: basket-db-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: basket-db + ports: + - port: 5432 + targetPort: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: basket-db + namespace: eshop-microservices +spec: + selector: + app: basket-db + ports: + - port: 5432 + targetPort: 5432 diff --git a/k8s/base/01-databases/basket-db/statefulset.yaml b/k8s/base/01-databases/basket-db/statefulset.yaml new file mode 100644 index 0000000..d3816f2 --- /dev/null +++ b/k8s/base/01-databases/basket-db/statefulset.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: basket-db + namespace: eshop-microservices +spec: + serviceName: basket-db-headless + replicas: 1 + selector: + matchLabels: + app: basket-db + template: + metadata: + labels: + app: basket-db + spec: + serviceAccountName: sa-databases + containers: + - name: postgres + image: postgres:16-alpine + env: + - name: POSTGRES_DB + value: BasketDb + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: basket-db-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: basket-db-secret + key: POSTGRES_PASSWORD + ports: + - containerPort: 5432 + livenessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 1Gi diff --git a/k8s/base/01-databases/catalog-db/service.yaml b/k8s/base/01-databases/catalog-db/service.yaml new file mode 100644 index 0000000..85bdfe0 --- /dev/null +++ b/k8s/base/01-databases/catalog-db/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: catalog-db-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: catalog-db + ports: + - port: 5432 + targetPort: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: catalog-db + namespace: eshop-microservices +spec: + selector: + app: catalog-db + ports: + - port: 5432 + targetPort: 5432 diff --git a/k8s/base/01-databases/catalog-db/statefulset.yaml b/k8s/base/01-databases/catalog-db/statefulset.yaml new file mode 100644 index 0000000..6aa0c02 --- /dev/null +++ b/k8s/base/01-databases/catalog-db/statefulset.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: catalog-db + namespace: eshop-microservices +spec: + serviceName: catalog-db-headless + replicas: 1 + selector: + matchLabels: + app: catalog-db + template: + metadata: + labels: + app: catalog-db + spec: + serviceAccountName: sa-databases + containers: + - name: postgres + image: postgres:16-alpine + env: + - name: POSTGRES_DB + value: CatalogDb + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: catalog-db-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: catalog-db-secret + key: POSTGRES_PASSWORD + ports: + - containerPort: 5432 + livenessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 1Gi diff --git a/k8s/base/01-databases/identity-db/service.yaml b/k8s/base/01-databases/identity-db/service.yaml new file mode 100644 index 0000000..1102a58 --- /dev/null +++ b/k8s/base/01-databases/identity-db/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: identity-db-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: identity-db + ports: + - port: 5432 + targetPort: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: identity-db + namespace: eshop-microservices +spec: + selector: + app: identity-db + ports: + - port: 5432 + targetPort: 5432 diff --git a/k8s/base/01-databases/identity-db/statefulset.yaml b/k8s/base/01-databases/identity-db/statefulset.yaml new file mode 100644 index 0000000..5aa19d2 --- /dev/null +++ b/k8s/base/01-databases/identity-db/statefulset.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: identity-db + namespace: eshop-microservices +spec: + serviceName: identity-db-headless + replicas: 1 + selector: + matchLabels: + app: identity-db + template: + metadata: + labels: + app: identity-db + spec: + serviceAccountName: sa-databases + containers: + - name: postgres + image: postgres:16-alpine + env: + - name: POSTGRES_DB + value: IdentityDb + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: identity-db-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: identity-db-secret + key: POSTGRES_PASSWORD + ports: + - containerPort: 5432 + livenessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 1Gi diff --git a/k8s/base/01-databases/kustomization.yaml b/k8s/base/01-databases/kustomization.yaml new file mode 100644 index 0000000..94eb233 --- /dev/null +++ b/k8s/base/01-databases/kustomization.yaml @@ -0,0 +1,20 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eshop-microservices + +resources: + - catalog-db/statefulset.yaml + - catalog-db/service.yaml + - basket-db/statefulset.yaml + - basket-db/service.yaml + - identity-db/statefulset.yaml + - identity-db/service.yaml + - order-command-db/statefulset.yaml + - order-command-db/service.yaml + - order-query-db/statefulset.yaml + - order-query-db/service.yaml + - redis/statefulset.yaml + - redis/service.yaml + - rabbitmq/statefulset.yaml + - rabbitmq/service.yaml diff --git a/k8s/base/01-databases/order-command-db/service.yaml b/k8s/base/01-databases/order-command-db/service.yaml new file mode 100644 index 0000000..6d3d6c0 --- /dev/null +++ b/k8s/base/01-databases/order-command-db/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: order-command-db-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: order-command-db + ports: + - port: 5432 + targetPort: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: order-command-db + namespace: eshop-microservices +spec: + selector: + app: order-command-db + ports: + - port: 5432 + targetPort: 5432 diff --git a/k8s/base/01-databases/order-command-db/statefulset.yaml b/k8s/base/01-databases/order-command-db/statefulset.yaml new file mode 100644 index 0000000..26c813c --- /dev/null +++ b/k8s/base/01-databases/order-command-db/statefulset.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: order-command-db + namespace: eshop-microservices +spec: + serviceName: order-command-db-headless + replicas: 1 + selector: + matchLabels: + app: order-command-db + template: + metadata: + labels: + app: order-command-db + spec: + serviceAccountName: sa-databases + containers: + - name: postgres + image: postgres:16-alpine + env: + - name: POSTGRES_DB + value: OrderCommandDb + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: order-command-db-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: order-command-db-secret + key: POSTGRES_PASSWORD + ports: + - containerPort: 5432 + livenessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 1Gi diff --git a/k8s/base/01-databases/order-query-db/service.yaml b/k8s/base/01-databases/order-query-db/service.yaml new file mode 100644 index 0000000..ec819eb --- /dev/null +++ b/k8s/base/01-databases/order-query-db/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: order-query-db-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: order-query-db + ports: + - port: 5432 + targetPort: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: order-query-db + namespace: eshop-microservices +spec: + selector: + app: order-query-db + ports: + - port: 5432 + targetPort: 5432 diff --git a/k8s/base/01-databases/order-query-db/statefulset.yaml b/k8s/base/01-databases/order-query-db/statefulset.yaml new file mode 100644 index 0000000..8b0e626 --- /dev/null +++ b/k8s/base/01-databases/order-query-db/statefulset.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: order-query-db + namespace: eshop-microservices +spec: + serviceName: order-query-db-headless + replicas: 1 + selector: + matchLabels: + app: order-query-db + template: + metadata: + labels: + app: order-query-db + spec: + serviceAccountName: sa-databases + containers: + - name: postgres + image: postgres:16-alpine + env: + - name: POSTGRES_DB + value: OrderQueryDb + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: order-query-db-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: order-query-db-secret + key: POSTGRES_PASSWORD + ports: + - containerPort: 5432 + livenessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: ["pg_isready", "-U", "postgres"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 1Gi diff --git a/k8s/base/01-databases/rabbitmq/service.yaml b/k8s/base/01-databases/rabbitmq/service.yaml new file mode 100644 index 0000000..29be564 --- /dev/null +++ b/k8s/base/01-databases/rabbitmq/service.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Service +metadata: + name: rabbitmq-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: rabbitmq + ports: + - port: 5672 + name: amqp + - port: 15672 + name: management +--- +apiVersion: v1 +kind: Service +metadata: + name: rabbitmq + namespace: eshop-microservices +spec: + selector: + app: rabbitmq + ports: + - port: 5672 + targetPort: 5672 + name: amqp + - port: 15672 + targetPort: 15672 + name: management diff --git a/k8s/base/01-databases/rabbitmq/statefulset.yaml b/k8s/base/01-databases/rabbitmq/statefulset.yaml new file mode 100644 index 0000000..8dd1f24 --- /dev/null +++ b/k8s/base/01-databases/rabbitmq/statefulset.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: rabbitmq + namespace: eshop-microservices +spec: + serviceName: rabbitmq-headless + replicas: 1 + selector: + matchLabels: + app: rabbitmq + template: + metadata: + labels: + app: rabbitmq + spec: + serviceAccountName: sa-databases + hostname: rabbitmq + containers: + - name: rabbitmq + image: rabbitmq:3-management-alpine + env: + - name: RABBITMQ_DEFAULT_USER + valueFrom: + secretKeyRef: + name: rabbitmq-secret + key: RABBITMQ_USERNAME + - name: RABBITMQ_DEFAULT_PASS + valueFrom: + secretKeyRef: + name: rabbitmq-secret + key: RABBITMQ_PASSWORD + ports: + - containerPort: 5672 + name: amqp + - containerPort: 15672 + name: management + livenessProbe: + exec: + command: ["rabbitmq-diagnostics", "ping"] + initialDelaySeconds: 60 + periodSeconds: 15 + failureThreshold: 5 + readinessProbe: + exec: + command: ["rabbitmq-diagnostics", "ping"] + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 3 + resources: + requests: + cpu: 200m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: data + mountPath: /var/lib/rabbitmq + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 1Gi diff --git a/k8s/base/01-databases/redis/service.yaml b/k8s/base/01-databases/redis/service.yaml new file mode 100644 index 0000000..fbf6826 --- /dev/null +++ b/k8s/base/01-databases/redis/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: redis + ports: + - port: 6379 + targetPort: 6379 +--- +apiVersion: v1 +kind: Service +metadata: + name: redis + namespace: eshop-microservices +spec: + selector: + app: redis + ports: + - port: 6379 + targetPort: 6379 diff --git a/k8s/base/01-databases/redis/statefulset.yaml b/k8s/base/01-databases/redis/statefulset.yaml new file mode 100644 index 0000000..830c594 --- /dev/null +++ b/k8s/base/01-databases/redis/statefulset.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: redis + namespace: eshop-microservices +spec: + serviceName: redis-headless + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + serviceAccountName: sa-databases + containers: + - name: redis + image: redis:alpine + ports: + - containerPort: 6379 + livenessProbe: + exec: + command: ["redis-cli", "ping"] + initialDelaySeconds: 15 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: ["redis-cli", "ping"] + initialDelaySeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 256Mi + volumeMounts: + - name: data + mountPath: /data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 512Mi diff --git a/k8s/base/02-observability/elasticsearch/service.yaml b/k8s/base/02-observability/elasticsearch/service.yaml new file mode 100644 index 0000000..e7bbcb0 --- /dev/null +++ b/k8s/base/02-observability/elasticsearch/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: elasticsearch-headless + namespace: eshop-microservices +spec: + clusterIP: None + selector: + app: elasticsearch + ports: + - port: 9200 + name: http + - port: 9300 + name: transport +--- +apiVersion: v1 +kind: Service +metadata: + name: elasticsearch + namespace: eshop-microservices +spec: + selector: + app: elasticsearch + ports: + - port: 9200 + targetPort: 9200 + name: http diff --git a/k8s/base/02-observability/elasticsearch/statefulset.yaml b/k8s/base/02-observability/elasticsearch/statefulset.yaml new file mode 100644 index 0000000..0a2d516 --- /dev/null +++ b/k8s/base/02-observability/elasticsearch/statefulset.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: elasticsearch + namespace: eshop-microservices +spec: + serviceName: elasticsearch-headless + replicas: 1 + selector: + matchLabels: + app: elasticsearch + template: + metadata: + labels: + app: elasticsearch + spec: + serviceAccountName: sa-observability + initContainers: + - name: fix-permissions + image: busybox:1.36 + command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"] + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data + containers: + - name: elasticsearch + image: docker.elastic.co/elasticsearch/elasticsearch:7.17.27 + env: + - name: discovery.type + value: single-node + - name: xpack.monitoring.enabled + value: "true" + - name: xpack.watcher.enabled + value: "false" + - name: ES_JAVA_OPTS + value: "-Xms512m -Xmx512m" + ports: + - containerPort: 9200 + name: http + - containerPort: 9300 + name: transport + livenessProbe: + httpGet: + path: /_cluster/health + port: 9200 + initialDelaySeconds: 60 + periodSeconds: 15 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /_cluster/health?wait_for_status=yellow + port: 9200 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: 1000m + memory: 2Gi + volumeMounts: + - name: data + mountPath: /usr/share/elasticsearch/data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 10Gi diff --git a/k8s/base/02-observability/grafana/deployment.yaml b/k8s/base/02-observability/grafana/deployment.yaml new file mode 100644 index 0000000..626c60d --- /dev/null +++ b/k8s/base/02-observability/grafana/deployment.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + serviceAccountName: sa-observability + containers: + - name: grafana + image: grafana/grafana:10.2.3 + env: + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: "Admin" + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "true" + ports: + - containerPort: 3000 + livenessProbe: + httpGet: + path: /api/health + port: 3000 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + initialDelaySeconds: 15 + periodSeconds: 5 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 300m + memory: 256Mi + volumeMounts: + - name: provisioning + mountPath: /etc/grafana/provisioning/datasources + volumes: + - name: provisioning + configMap: + name: grafana-provisioning diff --git a/k8s/base/02-observability/grafana/provisioning-cm.yaml b/k8s/base/02-observability/grafana/provisioning-cm.yaml new file mode 100644 index 0000000..4b1f8f3 --- /dev/null +++ b/k8s/base/02-observability/grafana/provisioning-cm.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-provisioning + namespace: eshop-microservices +data: + datasources.yaml: | + apiVersion: 1 + datasources: + - name: Prometheus + type: prometheus + uid: prometheus + url: http://prometheus:9090 + isDefault: true + access: proxy + editable: false + - name: Loki + type: loki + uid: loki + url: http://loki:3100 + access: proxy + editable: false + - name: Jaeger + type: jaeger + uid: jaeger + url: http://jaeger:16686 + access: proxy + editable: false diff --git a/k8s/base/02-observability/grafana/service.yaml b/k8s/base/02-observability/grafana/service.yaml new file mode 100644 index 0000000..93dca86 --- /dev/null +++ b/k8s/base/02-observability/grafana/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: eshop-microservices +spec: + selector: + app: grafana + ports: + - port: 3000 + targetPort: 3000 diff --git a/k8s/base/02-observability/jaeger/deployment.yaml b/k8s/base/02-observability/jaeger/deployment.yaml new file mode 100644 index 0000000..9922333 --- /dev/null +++ b/k8s/base/02-observability/jaeger/deployment.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: jaeger + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + spec: + serviceAccountName: sa-observability + containers: + - name: jaeger + image: jaegertracing/all-in-one:1.52 + args: + - "--query.ui-config=/etc/jaeger/jaeger-ui.json" + - "--collector.otlp.enabled=true" + - "--prometheus.server-url=http://prometheus:9090" + - "--prometheus.query.support-spanmetrics-connector=true" + env: + - name: METRICS_STORAGE_TYPE + value: prometheus + - name: PROMETHEUS_QUERY_NORMALIZE_CALLS + value: "true" + - name: PROMETHEUS_QUERY_NORMALIZE_DURATION + value: "true" + ports: + - containerPort: 16686 + name: ui + - containerPort: 14268 + name: collector-http + - containerPort: 14269 + name: admin + - containerPort: 4317 + name: otlp-grpc + - containerPort: 6831 + name: agent-udp + protocol: UDP + livenessProbe: + httpGet: + path: / + port: 14269 + initialDelaySeconds: 20 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 14269 + initialDelaySeconds: 10 + periodSeconds: 5 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: jaeger-ui-config + mountPath: /etc/jaeger + volumes: + - name: jaeger-ui-config + configMap: + name: jaeger-ui-config diff --git a/k8s/base/02-observability/jaeger/service.yaml b/k8s/base/02-observability/jaeger/service.yaml new file mode 100644 index 0000000..5511a6e --- /dev/null +++ b/k8s/base/02-observability/jaeger/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: jaeger + namespace: eshop-microservices +spec: + selector: + app: jaeger + ports: + - port: 16686 + targetPort: 16686 + name: ui + - port: 14268 + targetPort: 14268 + name: collector-http + - port: 14269 + targetPort: 14269 + name: admin + - port: 4317 + targetPort: 4317 + name: otlp-grpc + - port: 6831 + targetPort: 6831 + protocol: UDP + name: agent-udp diff --git a/k8s/base/02-observability/kibana/deployment.yaml b/k8s/base/02-observability/kibana/deployment.yaml new file mode 100644 index 0000000..a4f3cb6 --- /dev/null +++ b/k8s/base/02-observability/kibana/deployment.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kibana + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: kibana + template: + metadata: + labels: + app: kibana + spec: + serviceAccountName: sa-observability + containers: + - name: kibana + image: docker.elastic.co/kibana/kibana:7.17.27 + env: + - name: ELASTICSEARCH_HOSTS + value: "http://elasticsearch:9200" + ports: + - containerPort: 5601 + livenessProbe: + httpGet: + path: /api/status + port: 5601 + initialDelaySeconds: 60 + periodSeconds: 15 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /api/status + port: 5601 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi diff --git a/k8s/base/02-observability/kibana/service.yaml b/k8s/base/02-observability/kibana/service.yaml new file mode 100644 index 0000000..3a45f96 --- /dev/null +++ b/k8s/base/02-observability/kibana/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: kibana + namespace: eshop-microservices +spec: + selector: + app: kibana + ports: + - port: 5601 + targetPort: 5601 diff --git a/k8s/base/02-observability/kustomization.yaml b/k8s/base/02-observability/kustomization.yaml new file mode 100644 index 0000000..1c27f78 --- /dev/null +++ b/k8s/base/02-observability/kustomization.yaml @@ -0,0 +1,23 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eshop-microservices + +resources: + - elasticsearch/statefulset.yaml + - elasticsearch/service.yaml + - kibana/deployment.yaml + - kibana/service.yaml + - otel-collector/deployment.yaml + - otel-collector/service.yaml + - jaeger/deployment.yaml + - jaeger/service.yaml + - prometheus/pvc.yaml + - prometheus/deployment.yaml + - prometheus/service.yaml + - loki/pvc.yaml + - loki/deployment.yaml + - loki/service.yaml + - grafana/provisioning-cm.yaml + - grafana/deployment.yaml + - grafana/service.yaml diff --git a/k8s/base/02-observability/loki/deployment.yaml b/k8s/base/02-observability/loki/deployment.yaml new file mode 100644 index 0000000..f8eb71e --- /dev/null +++ b/k8s/base/02-observability/loki/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: loki + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: loki + template: + metadata: + labels: + app: loki + spec: + serviceAccountName: sa-observability + containers: + - name: loki + image: grafana/loki:2.9.3 + args: + - "-config.file=/mnt/config/loki-config.yml" + ports: + - containerPort: 3100 + livenessProbe: + httpGet: + path: /ready + port: 3100 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 3100 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 300m + memory: 512Mi + volumeMounts: + - name: config + mountPath: /mnt/config + - name: data + mountPath: /tmp/loki + volumes: + - name: config + configMap: + name: loki-config + - name: data + persistentVolumeClaim: + claimName: loki-pvc diff --git a/k8s/base/02-observability/loki/pvc.yaml b/k8s/base/02-observability/loki/pvc.yaml new file mode 100644 index 0000000..40e940b --- /dev/null +++ b/k8s/base/02-observability/loki/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: loki-pvc + namespace: eshop-microservices +spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 5Gi diff --git a/k8s/base/02-observability/loki/service.yaml b/k8s/base/02-observability/loki/service.yaml new file mode 100644 index 0000000..fc72ed0 --- /dev/null +++ b/k8s/base/02-observability/loki/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: loki + namespace: eshop-microservices +spec: + selector: + app: loki + ports: + - port: 3100 + targetPort: 3100 diff --git a/k8s/base/02-observability/otel-collector/deployment.yaml b/k8s/base/02-observability/otel-collector/deployment.yaml new file mode 100644 index 0000000..58ae8ad --- /dev/null +++ b/k8s/base/02-observability/otel-collector/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: otel-collector + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: otel-collector + template: + metadata: + labels: + app: otel-collector + spec: + serviceAccountName: sa-observability + containers: + - name: otel-collector + image: otel/opentelemetry-collector-contrib:0.91.0 + args: + - "--config=/etc/otelcol/otel-collector-config.yml" + ports: + - containerPort: 4317 + name: otlp-grpc + - containerPort: 4318 + name: otlp-http + - containerPort: 8889 + name: prometheus + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: config + mountPath: /etc/otelcol + volumes: + - name: config + configMap: + name: otel-collector-config diff --git a/k8s/base/02-observability/otel-collector/service.yaml b/k8s/base/02-observability/otel-collector/service.yaml new file mode 100644 index 0000000..45f6798 --- /dev/null +++ b/k8s/base/02-observability/otel-collector/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: otel-collector + namespace: eshop-microservices +spec: + selector: + app: otel-collector + ports: + - port: 4317 + targetPort: 4317 + name: otlp-grpc + - port: 4318 + targetPort: 4318 + name: otlp-http + - port: 8889 + targetPort: 8889 + name: prometheus diff --git a/k8s/base/02-observability/prometheus/deployment.yaml b/k8s/base/02-observability/prometheus/deployment.yaml new file mode 100644 index 0000000..398898e --- /dev/null +++ b/k8s/base/02-observability/prometheus/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + serviceAccountName: sa-observability + securityContext: + fsGroup: 65534 + runAsUser: 65534 + runAsNonRoot: true + containers: + - name: prometheus + image: prom/prometheus:v2.48.1 + ports: + - containerPort: 9090 + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + initialDelaySeconds: 20 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + initialDelaySeconds: 10 + periodSeconds: 5 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 1Gi + volumeMounts: + - name: config + mountPath: /etc/prometheus + - name: data + mountPath: /prometheus + volumes: + - name: config + configMap: + name: prometheus-config + - name: data + persistentVolumeClaim: + claimName: prometheus-pvc diff --git a/k8s/base/02-observability/prometheus/pvc.yaml b/k8s/base/02-observability/prometheus/pvc.yaml new file mode 100644 index 0000000..07912c8 --- /dev/null +++ b/k8s/base/02-observability/prometheus/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: prometheus-pvc + namespace: eshop-microservices +spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 5Gi diff --git a/k8s/base/02-observability/prometheus/service.yaml b/k8s/base/02-observability/prometheus/service.yaml new file mode 100644 index 0000000..8b85661 --- /dev/null +++ b/k8s/base/02-observability/prometheus/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: eshop-microservices +spec: + selector: + app: prometheus + ports: + - port: 9090 + targetPort: 9090 diff --git a/k8s/base/03-mail/kustomization.yaml b/k8s/base/03-mail/kustomization.yaml new file mode 100644 index 0000000..19801f6 --- /dev/null +++ b/k8s/base/03-mail/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eshop-microservices + +resources: + - mailpit/pvc.yaml + - mailpit/deployment.yaml + - mailpit/service.yaml diff --git a/k8s/base/03-mail/mailpit/deployment.yaml b/k8s/base/03-mail/mailpit/deployment.yaml new file mode 100644 index 0000000..9774509 --- /dev/null +++ b/k8s/base/03-mail/mailpit/deployment.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mailpit + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: mailpit + template: + metadata: + labels: + app: mailpit + spec: + containers: + - name: mailpit + image: axllent/mailpit:latest + env: + - name: MP_MAX_MESSAGES + value: "5000" + - name: MP_DATABASE + value: "/data/mailpit.db" + - name: MP_SMTP_AUTH_ACCEPT_ANY + value: "1" + - name: MP_SMTP_AUTH_ALLOW_INSECURE + value: "1" + ports: + - containerPort: 8025 + name: ui + - containerPort: 1025 + name: smtp + livenessProbe: + httpGet: + path: /livez + port: 8025 + initialDelaySeconds: 10 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /readyz + port: 8025 + initialDelaySeconds: 5 + periodSeconds: 5 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 256Mi + volumeMounts: + - name: data + mountPath: /data + volumes: + - name: data + persistentVolumeClaim: + claimName: mailpit-pvc diff --git a/k8s/base/03-mail/mailpit/pvc.yaml b/k8s/base/03-mail/mailpit/pvc.yaml new file mode 100644 index 0000000..494dedd --- /dev/null +++ b/k8s/base/03-mail/mailpit/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mailpit-pvc + namespace: eshop-microservices +spec: + accessModes: [ReadWriteOnce] + storageClassName: standard + resources: + requests: + storage: 512Mi diff --git a/k8s/base/03-mail/mailpit/service.yaml b/k8s/base/03-mail/mailpit/service.yaml new file mode 100644 index 0000000..8ee518b --- /dev/null +++ b/k8s/base/03-mail/mailpit/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: mailpit + namespace: eshop-microservices +spec: + selector: + app: mailpit + ports: + - port: 8025 + targetPort: 8025 + name: ui + - port: 1025 + targetPort: 1025 + name: smtp diff --git a/k8s/base/04-services/api-gateway/deployment.yaml b/k8s/base/04-services/api-gateway/deployment.yaml new file mode 100644 index 0000000..2f167c6 --- /dev/null +++ b/k8s/base/04-services/api-gateway/deployment.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: api-gateway + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: api-gateway + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: api-gateway + spec: + serviceAccountName: sa-api-gateway + containers: + - name: api-gateway + image: api.gateway:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: api-gateway-cm + env: + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-api-gateway + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/api-gateway/hpa.yaml b/k8s/base/04-services/api-gateway/hpa.yaml new file mode 100644 index 0000000..534ae50 --- /dev/null +++ b/k8s/base/04-services/api-gateway/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: api-gateway-hpa + namespace: eshop-microservices +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: api-gateway + minReplicas: 1 + maxReplicas: 3 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/k8s/base/04-services/api-gateway/service.yaml b/k8s/base/04-services/api-gateway/service.yaml new file mode 100644 index 0000000..06cd69a --- /dev/null +++ b/k8s/base/04-services/api-gateway/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: api-gateway + namespace: eshop-microservices +spec: + selector: + app: api-gateway + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/basket-api/deployment.yaml b/k8s/base/04-services/basket-api/deployment.yaml new file mode 100644 index 0000000..b560ba2 --- /dev/null +++ b/k8s/base/04-services/basket-api/deployment.yaml @@ -0,0 +1,91 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: basket-api + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: basket-api + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: basket-api + spec: + serviceAccountName: sa-basket-api + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z basket-db 5432; do echo waiting for basket-db; sleep 2; done'] + - name: wait-for-redis + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z redis 6379; do echo waiting for redis; sleep 2; done'] + containers: + - name: basket-api + image: basket.api:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: basket-api-cm + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: basket-db-secret + key: POSTGRES_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: basket-db-secret + key: POSTGRES_PASSWORD + - name: ConnectionStrings__Database + value: "Server=basket-db;Port=5432;Database=BasketDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-basket-api + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/basket-api/hpa.yaml b/k8s/base/04-services/basket-api/hpa.yaml new file mode 100644 index 0000000..de68af5 --- /dev/null +++ b/k8s/base/04-services/basket-api/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: basket-api-hpa + namespace: eshop-microservices +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: basket-api + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/k8s/base/04-services/basket-api/service.yaml b/k8s/base/04-services/basket-api/service.yaml new file mode 100644 index 0000000..bc4f0e3 --- /dev/null +++ b/k8s/base/04-services/basket-api/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: basket-api + namespace: eshop-microservices +spec: + selector: + app: basket-api + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/catalog-api/deployment.yaml b/k8s/base/04-services/catalog-api/deployment.yaml new file mode 100644 index 0000000..1c666e9 --- /dev/null +++ b/k8s/base/04-services/catalog-api/deployment.yaml @@ -0,0 +1,88 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: catalog-api + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: catalog-api + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: catalog-api + spec: + serviceAccountName: sa-catalog-api + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z catalog-db 5432; do echo waiting for catalog-db; sleep 2; done'] + containers: + - name: catalog-api + image: catalog.api:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: catalog-api-cm + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: catalog-db-secret + key: POSTGRES_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: catalog-db-secret + key: POSTGRES_PASSWORD + - name: ConnectionStrings__Database + value: "Server=catalog-db;Port=5432;Database=CatalogDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-catalog-api + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/catalog-api/hpa.yaml b/k8s/base/04-services/catalog-api/hpa.yaml new file mode 100644 index 0000000..302dbd5 --- /dev/null +++ b/k8s/base/04-services/catalog-api/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: catalog-api-hpa + namespace: eshop-microservices +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: catalog-api + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/k8s/base/04-services/catalog-api/service.yaml b/k8s/base/04-services/catalog-api/service.yaml new file mode 100644 index 0000000..647f314 --- /dev/null +++ b/k8s/base/04-services/catalog-api/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: catalog-api + namespace: eshop-microservices +spec: + selector: + app: catalog-api + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/discount-grpc/deployment.yaml b/k8s/base/04-services/discount-grpc/deployment.yaml new file mode 100644 index 0000000..0d39ad3 --- /dev/null +++ b/k8s/base/04-services/discount-grpc/deployment.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: discount-grpc + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: discount-grpc + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: discount-grpc + spec: + serviceAccountName: sa-discount-grpc + containers: + - name: discount-grpc + image: discount.grpc:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: discount-grpc-cm + env: + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: grpc + - containerPort: 8081 + name: https + livenessProbe: + grpc: + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + grpc: + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 300m + memory: 256Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + - name: sqlite-data + mountPath: /app/data + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-discount-grpc + - configMap: + name: cert-ca + - name: sqlite-data + emptyDir: {} diff --git a/k8s/base/04-services/discount-grpc/service.yaml b/k8s/base/04-services/discount-grpc/service.yaml new file mode 100644 index 0000000..9a116f8 --- /dev/null +++ b/k8s/base/04-services/discount-grpc/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: discount-grpc + namespace: eshop-microservices +spec: + selector: + app: discount-grpc + ports: + - port: 8080 + targetPort: 8080 + name: grpc + appProtocol: kubernetes.io/h2c + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/identity-api/deployment.yaml b/k8s/base/04-services/identity-api/deployment.yaml new file mode 100644 index 0000000..eeeb2f5 --- /dev/null +++ b/k8s/base/04-services/identity-api/deployment.yaml @@ -0,0 +1,93 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: identity-api + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: identity-api + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: identity-api + spec: + serviceAccountName: sa-identity-api + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z identity-db 5432; do echo waiting for identity-db; sleep 2; done'] + containers: + - name: identity-api + image: identity.api:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: identity-api-cm + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: identity-db-secret + key: POSTGRES_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: identity-db-secret + key: POSTGRES_PASSWORD + - name: ConnectionStrings__IdentityDB + value: "Host=identity-db;Port=5432;Database=IdentityDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" + - name: EmailService__authentication_key + valueFrom: + secretKeyRef: + name: identity-secret + key: EmailService__authentication_key + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-identity-api + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/identity-api/hpa.yaml b/k8s/base/04-services/identity-api/hpa.yaml new file mode 100644 index 0000000..7f277e3 --- /dev/null +++ b/k8s/base/04-services/identity-api/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: identity-api-hpa + namespace: eshop-microservices +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: identity-api + minReplicas: 1 + maxReplicas: 3 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/k8s/base/04-services/identity-api/service.yaml b/k8s/base/04-services/identity-api/service.yaml new file mode 100644 index 0000000..f84b6c3 --- /dev/null +++ b/k8s/base/04-services/identity-api/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: identity-api + namespace: eshop-microservices +spec: + selector: + app: identity-api + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/kustomization.yaml b/k8s/base/04-services/kustomization.yaml new file mode 100644 index 0000000..483c4e8 --- /dev/null +++ b/k8s/base/04-services/kustomization.yaml @@ -0,0 +1,30 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eshop-microservices + +resources: + - catalog-api/deployment.yaml + - catalog-api/service.yaml + - catalog-api/hpa.yaml + - basket-api/deployment.yaml + - basket-api/service.yaml + - basket-api/hpa.yaml + - discount-grpc/deployment.yaml + - discount-grpc/service.yaml + - identity-api/deployment.yaml + - identity-api/service.yaml + - identity-api/hpa.yaml + - order-command-api/deployment.yaml + - order-command-api/service.yaml + - order-command-api/hpa.yaml + - order-query-api/deployment.yaml + - order-query-api/service.yaml + - order-query-api/hpa.yaml + - order-query-eventprocessor/deployment.yaml + - order-query-eventprocessor/service.yaml + - api-gateway/deployment.yaml + - api-gateway/service.yaml + - api-gateway/hpa.yaml + - network-policies.yaml + - pod-disruption-budgets.yaml diff --git a/k8s/base/04-services/network-policies.yaml b/k8s/base/04-services/network-policies.yaml new file mode 100644 index 0000000..81a2d68 --- /dev/null +++ b/k8s/base/04-services/network-policies.yaml @@ -0,0 +1,617 @@ +# Default deny-all ingress in namespace +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-ingress + namespace: eshop-microservices +spec: + podSelector: {} + policyTypes: + - Ingress +--- +# Default deny-all egress in namespace +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-egress + namespace: eshop-microservices +spec: + podSelector: {} + policyTypes: + - Egress +--- +# Allow DNS resolution for all pods (required for service discovery) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-dns-egress + namespace: eshop-microservices +spec: + podSelector: {} + policyTypes: + - Egress + egress: + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP +--- +# catalog-api +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-catalog-api + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: catalog-api + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app: api-gateway + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx + egress: + - to: + - podSelector: + matchLabels: + app: catalog-db + ports: + - port: 5432 + - to: + - podSelector: + matchLabels: + app: elasticsearch + ports: + - port: 9200 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 + - to: + - podSelector: + matchLabels: + app: identity-api + ports: + - port: 8081 +--- +# basket-api +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-basket-api + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: basket-api + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app: api-gateway + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx + egress: + - to: + - podSelector: + matchLabels: + app: basket-db + ports: + - port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - port: 6379 + - to: + - podSelector: + matchLabels: + app: discount-grpc + ports: + - port: 8080 + - to: + - podSelector: + matchLabels: + app: order-command-api + ports: + - port: 8080 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 + - to: + - podSelector: + matchLabels: + app: identity-api + ports: + - port: 8081 +--- +# discount-grpc +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-discount-grpc + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: discount-grpc + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app: basket-api + ports: + - port: 8080 + - from: + - podSelector: + matchLabels: + app: api-gateway + ports: + - port: 8081 + egress: + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 +--- +# identity-api — allow all pods to reach it (for JWT validation) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-identity-api + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: identity-api + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: {} + ports: + - port: 8081 + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx + egress: + - to: + - podSelector: + matchLabels: + app: identity-db + ports: + - port: 5432 + - to: + - podSelector: + matchLabels: + app: mailpit + ports: + - port: 1025 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 +--- +# order-command-api +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-order-command-api + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: order-command-api + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app: api-gateway + - podSelector: + matchLabels: + app: basket-api + egress: + - to: + - podSelector: + matchLabels: + app: order-command-db + ports: + - port: 5432 + - to: + - podSelector: + matchLabels: + app: rabbitmq + ports: + - port: 5672 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 + - to: + - podSelector: + matchLabels: + app: identity-api + ports: + - port: 8081 +--- +# order-query-api +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-order-query-api + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: order-query-api + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app: api-gateway + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx + egress: + - to: + - podSelector: + matchLabels: + app: order-query-db + ports: + - port: 5432 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 + - to: + - podSelector: + matchLabels: + app: identity-api + ports: + - port: 8081 +--- +# order-query-eventprocessor (background worker, no ingress) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-order-query-eventprocessor + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: order-query-eventprocessor + policyTypes: + - Ingress + - Egress + ingress: [] + egress: + - to: + - podSelector: + matchLabels: + app: order-query-db + ports: + - port: 5432 + - to: + - podSelector: + matchLabels: + app: rabbitmq + ports: + - port: 5672 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 +--- +# api-gateway +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-api-gateway + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: api-gateway + policyTypes: + - Ingress + - Egress + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx + egress: + - to: + - podSelector: + matchLabels: + app: catalog-api + ports: + - port: 8081 + - to: + - podSelector: + matchLabels: + app: basket-api + ports: + - port: 8081 + - to: + - podSelector: + matchLabels: + app: discount-grpc + ports: + - port: 8081 + - to: + - podSelector: + matchLabels: + app: order-command-api + ports: + - port: 8081 + - to: + - podSelector: + matchLabels: + app: order-query-api + ports: + - port: 8081 + - to: + - podSelector: + matchLabels: + app: identity-api + ports: + - port: 8081 + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - port: 4317 + - port: 4318 +--- +# Database policies +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-catalog-db + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: catalog-db + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: catalog-api + ports: + - port: 5432 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-basket-db + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: basket-db + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: basket-api + ports: + - port: 5432 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-identity-db + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: identity-db + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: identity-api + ports: + - port: 5432 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-order-command-db + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: order-command-db + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: order-command-api + ports: + - port: 5432 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-order-query-db + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: order-query-db + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: order-query-api + - podSelector: + matchLabels: + app: order-query-eventprocessor + ports: + - port: 5432 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-redis + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: redis + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: basket-api + ports: + - port: 6379 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-rabbitmq + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: rabbitmq + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app: order-command-api + - podSelector: + matchLabels: + app: order-query-eventprocessor + ports: + - port: 5672 +--- +# OTEL Collector +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-otel-collector + namespace: eshop-microservices +spec: + podSelector: + matchLabels: + app: otel-collector + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: {} + ports: + - port: 4317 + - port: 4318 + - from: + - podSelector: + matchLabels: + app: prometheus + ports: + - port: 8889 + egress: + - to: + - podSelector: + matchLabels: + app: jaeger + ports: + - port: 4317 + - to: + - podSelector: + matchLabels: + app: loki + ports: + - port: 3100 + - to: + - podSelector: + matchLabels: + app: prometheus + ports: + - port: 9090 +--- +# Observability UIs — allow ingress from ingress-nginx +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: netpol-observability-uis + namespace: eshop-microservices +spec: + podSelector: + matchExpressions: + - key: app + operator: In + values: [kibana, jaeger, grafana, prometheus, mailpit] + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx diff --git a/k8s/base/04-services/order-command-api/deployment.yaml b/k8s/base/04-services/order-command-api/deployment.yaml new file mode 100644 index 0000000..c2f77eb --- /dev/null +++ b/k8s/base/04-services/order-command-api/deployment.yaml @@ -0,0 +1,101 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: order-command-api + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: order-command-api + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: order-command-api + spec: + serviceAccountName: sa-order-command-api + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z order-command-db 5432; do echo waiting for order-command-db; sleep 2; done'] + - name: wait-for-rabbitmq + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z rabbitmq 5672; do echo waiting for rabbitmq; sleep 2; done'] + containers: + - name: order-command-api + image: order.command.api:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: order-command-api-cm + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: order-command-db-secret + key: POSTGRES_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: order-command-db-secret + key: POSTGRES_PASSWORD + - name: ConnectionStrings__Database + value: "Server=order-command-db;Database=OrderCommandDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" + - name: RabbitMQ__Username + valueFrom: + secretKeyRef: + name: rabbitmq-secret + key: RABBITMQ_USERNAME + - name: RabbitMQ__Password + valueFrom: + secretKeyRef: + name: rabbitmq-secret + key: RABBITMQ_PASSWORD + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-order-command-api + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/order-command-api/hpa.yaml b/k8s/base/04-services/order-command-api/hpa.yaml new file mode 100644 index 0000000..e0e0390 --- /dev/null +++ b/k8s/base/04-services/order-command-api/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: order-command-api-hpa + namespace: eshop-microservices +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: order-command-api + minReplicas: 1 + maxReplicas: 3 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/k8s/base/04-services/order-command-api/service.yaml b/k8s/base/04-services/order-command-api/service.yaml new file mode 100644 index 0000000..543baf8 --- /dev/null +++ b/k8s/base/04-services/order-command-api/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: order-command-api + namespace: eshop-microservices +spec: + selector: + app: order-command-api + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/order-query-api/deployment.yaml b/k8s/base/04-services/order-query-api/deployment.yaml new file mode 100644 index 0000000..a9dbc9d --- /dev/null +++ b/k8s/base/04-services/order-query-api/deployment.yaml @@ -0,0 +1,88 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: order-query-api + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: order-query-api + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: order-query-api + spec: + serviceAccountName: sa-order-query-api + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z order-query-db 5432; do echo waiting for order-query-db; sleep 2; done'] + containers: + - name: order-query-api + image: order.query.api:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: order-query-api-cm + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: order-query-db-secret + key: POSTGRES_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: order-query-db-secret + key: POSTGRES_PASSWORD + - name: ConnectionStrings__Database + value: "Host=order-query-db;Port=5432;Database=OrderQueryDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-order-query-api + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/order-query-api/hpa.yaml b/k8s/base/04-services/order-query-api/hpa.yaml new file mode 100644 index 0000000..6422a42 --- /dev/null +++ b/k8s/base/04-services/order-query-api/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: order-query-api-hpa + namespace: eshop-microservices +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: order-query-api + minReplicas: 1 + maxReplicas: 3 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/k8s/base/04-services/order-query-api/service.yaml b/k8s/base/04-services/order-query-api/service.yaml new file mode 100644 index 0000000..13bd7b3 --- /dev/null +++ b/k8s/base/04-services/order-query-api/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: order-query-api + namespace: eshop-microservices +spec: + selector: + app: order-query-api + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/order-query-eventprocessor/deployment.yaml b/k8s/base/04-services/order-query-eventprocessor/deployment.yaml new file mode 100644 index 0000000..aa278ce --- /dev/null +++ b/k8s/base/04-services/order-query-eventprocessor/deployment.yaml @@ -0,0 +1,101 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: order-query-eventprocessor + namespace: eshop-microservices +spec: + replicas: 1 + selector: + matchLabels: + app: order-query-eventprocessor + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: order-query-eventprocessor + spec: + serviceAccountName: sa-order-query-eventprocessor + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z order-query-db 5432; do echo waiting for order-query-db; sleep 2; done'] + - name: wait-for-rabbitmq + image: busybox:1.36 + command: ['sh', '-c', 'until nc -z rabbitmq 5672; do echo waiting for rabbitmq; sleep 2; done'] + containers: + - name: order-query-eventprocessor + image: order.query.eventprocessor:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: order-query-eventprocessor-cm + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: order-query-db-secret + key: POSTGRES_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: order-query-db-secret + key: POSTGRES_PASSWORD + - name: ConnectionStrings__Database + value: "Host=order-query-db;Port=5432;Database=OrderQueryDb;User Id=$(DB_USER);Password=$(DB_PASSWORD)" + - name: RabbitMQ__Username + valueFrom: + secretKeyRef: + name: rabbitmq-secret + key: RABBITMQ_USERNAME + - name: RabbitMQ__Password + valueFrom: + secretKeyRef: + name: rabbitmq-secret + key: RABBITMQ_PASSWORD + - name: ASPNETCORE_Kestrel__Certificates__Default__Password + valueFrom: + secretKeyRef: + name: cert-password + key: CERT_PASSWORD + ports: + - containerPort: 8080 + name: http + - containerPort: 8081 + name: https + livenessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /hc + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 300m + memory: 512Mi + volumeMounts: + - name: certs + mountPath: /app/certificates + readOnly: true + volumes: + - name: certs + projected: + sources: + - secret: + name: cert-order-query-eventprocessor + - configMap: + name: cert-ca diff --git a/k8s/base/04-services/order-query-eventprocessor/service.yaml b/k8s/base/04-services/order-query-eventprocessor/service.yaml new file mode 100644 index 0000000..67f6d12 --- /dev/null +++ b/k8s/base/04-services/order-query-eventprocessor/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: order-query-eventprocessor + namespace: eshop-microservices +spec: + selector: + app: order-query-eventprocessor + ports: + - port: 8080 + targetPort: 8080 + name: http + - port: 8081 + targetPort: 8081 + name: https diff --git a/k8s/base/04-services/pod-disruption-budgets.yaml b/k8s/base/04-services/pod-disruption-budgets.yaml new file mode 100644 index 0000000..5f9b2d9 --- /dev/null +++ b/k8s/base/04-services/pod-disruption-budgets.yaml @@ -0,0 +1,175 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-catalog-api + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: catalog-api +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-basket-api + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: basket-api +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-discount-grpc + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: discount-grpc +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-identity-api + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: identity-api +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-order-command-api + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: order-command-api +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-order-query-api + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: order-query-api +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-order-query-eventprocessor + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: order-query-eventprocessor +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-api-gateway + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: api-gateway +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-catalog-db + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: catalog-db +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-basket-db + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: basket-db +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-identity-db + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: identity-db +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-order-command-db + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: order-command-db +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-order-query-db + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: order-query-db +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-redis + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: redis +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-rabbitmq + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: rabbitmq +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pdb-elasticsearch + namespace: eshop-microservices +spec: + minAvailable: 1 + selector: + matchLabels: + app: elasticsearch diff --git a/k8s/base/05-ingress/ingress.yaml b/k8s/base/05-ingress/ingress.yaml new file mode 100644 index 0000000..e777e02 --- /dev/null +++ b/k8s/base/05-ingress/ingress.yaml @@ -0,0 +1,197 @@ +# api-gateway — HTTPS backend +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-api-gateway + namespace: eshop-microservices + annotations: + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/proxy-ssl-verify: "false" +spec: + ingressClassName: nginx + tls: + - hosts: + - api.eshop.local + secretName: ingress-tls + rules: + - host: api.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: api-gateway + port: + number: 8081 +--- +# identity-api — HTTPS backend +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-identity-api + namespace: eshop-microservices + annotations: + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/proxy-ssl-verify: "false" +spec: + ingressClassName: nginx + tls: + - hosts: + - identity.eshop.local + secretName: ingress-tls + rules: + - host: identity.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: identity-api + port: + number: 8081 +--- +# mailpit UI +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-mailpit + namespace: eshop-microservices +spec: + ingressClassName: nginx + tls: + - hosts: + - mailpit.eshop.local + secretName: ingress-tls + rules: + - host: mailpit.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mailpit + port: + number: 8025 +--- +# kibana +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-kibana + namespace: eshop-microservices +spec: + ingressClassName: nginx + tls: + - hosts: + - kibana.eshop.local + secretName: ingress-tls + rules: + - host: kibana.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: kibana + port: + number: 5601 +--- +# jaeger UI +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-jaeger + namespace: eshop-microservices +spec: + ingressClassName: nginx + tls: + - hosts: + - jaeger.eshop.local + secretName: ingress-tls + rules: + - host: jaeger.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: jaeger + port: + number: 16686 +--- +# grafana +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-grafana + namespace: eshop-microservices +spec: + ingressClassName: nginx + tls: + - hosts: + - grafana.eshop.local + secretName: ingress-tls + rules: + - host: grafana.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: grafana + port: + number: 3000 +--- +# prometheus +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-prometheus + namespace: eshop-microservices +spec: + ingressClassName: nginx + tls: + - hosts: + - prometheus.eshop.local + secretName: ingress-tls + rules: + - host: prometheus.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prometheus + port: + number: 9090 +--- +# rabbitmq management UI +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-rabbitmq + namespace: eshop-microservices +spec: + ingressClassName: nginx + tls: + - hosts: + - rabbitmq.eshop.local + secretName: ingress-tls + rules: + - host: rabbitmq.eshop.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: rabbitmq + port: + number: 15672 diff --git a/k8s/base/05-ingress/kustomization.yaml b/k8s/base/05-ingress/kustomization.yaml new file mode 100644 index 0000000..7879232 --- /dev/null +++ b/k8s/base/05-ingress/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: eshop-microservices + +resources: + - ingress.yaml diff --git a/k8s/base/kustomization.yaml b/k8s/base/kustomization.yaml new file mode 100644 index 0000000..f13d7aa --- /dev/null +++ b/k8s/base/kustomization.yaml @@ -0,0 +1,10 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - 00-core + - 01-databases + - 02-observability + - 03-mail + - 04-services + - 05-ingress diff --git a/k8s/overlays/local/kustomization.yaml b/k8s/overlays/local/kustomization.yaml new file mode 100644 index 0000000..fc0fbf9 --- /dev/null +++ b/k8s/overlays/local/kustomization.yaml @@ -0,0 +1,49 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +patches: + - path: patches/resource-limits-patch.yaml + target: + kind: StatefulSet + name: elasticsearch + - patch: |- + - op: replace + path: /spec/volumeClaimTemplates/0/spec/storageClassName + value: local-path + target: + kind: StatefulSet + - patch: |- + - op: replace + path: /spec/storageClassName + value: local-path + target: + kind: PersistentVolumeClaim + +images: + - name: catalog.api + newName: catalog.api + newTag: latest + - name: basket.api + newName: basket.api + newTag: latest + - name: discount.grpc + newName: discount.grpc + newTag: latest + - name: identity.api + newName: identity.api + newTag: latest + - name: order.command.api + newName: order.command.api + newTag: latest + - name: order.query.api + newName: order.query.api + newTag: latest + - name: order.query.eventprocessor + newName: order.query.eventprocessor + newTag: latest + - name: api.gateway + newName: api.gateway + newTag: latest diff --git a/k8s/overlays/local/patches/resource-limits-patch.yaml b/k8s/overlays/local/patches/resource-limits-patch.yaml new file mode 100644 index 0000000..79c7c02 --- /dev/null +++ b/k8s/overlays/local/patches/resource-limits-patch.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: elasticsearch + namespace: eshop-microservices +spec: + template: + spec: + containers: + - name: elasticsearch + env: + - name: ES_JAVA_OPTS + value: "-Xms256m -Xmx256m" + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + storageClassName: local-path + resources: + requests: + storage: 2Gi diff --git a/k8s/overlays/local/patches/single-replica-patch.yaml b/k8s/overlays/local/patches/single-replica-patch.yaml new file mode 100644 index 0000000..b485eca --- /dev/null +++ b/k8s/overlays/local/patches/single-replica-patch.yaml @@ -0,0 +1,9 @@ +# All StatefulSets are already set to replicas: 1 in base manifests, suitable for local dev. +# This file is a placeholder. For production overlay, patch replicas here to 2+ with proper HA. +# For now, local single-replica is the correct configuration. +# apiVersion: apps/v1 +# kind: StatefulSet +# metadata: +# name: -db +# spec: +# replicas: 2 # production example diff --git a/k8s/overlays/local/patches/storage-class-patch.yaml b/k8s/overlays/local/patches/storage-class-patch.yaml new file mode 100644 index 0000000..241109e --- /dev/null +++ b/k8s/overlays/local/patches/storage-class-patch.yaml @@ -0,0 +1,12 @@ +# Storage class is already set to 'standard' in base manifests, which works for minikube/kind/Docker Desktop. +# This file is a placeholder. For production overlay, patch storageClassName here: +# apiVersion: apps/v1 +# kind: StatefulSet +# metadata: +# name: -db +# spec: +# volumeClaimTemplates: +# - metadata: +# name: data +# spec: +# storageClassName: pd-ssd # GKE example diff --git a/k8s/overlays/production/kustomization.yaml b/k8s/overlays/production/kustomization.yaml new file mode 100644 index 0000000..1556610 --- /dev/null +++ b/k8s/overlays/production/kustomization.yaml @@ -0,0 +1,12 @@ +# Production overlay — placeholder only. Implement when targeting a cloud cluster. +# This overlay should patch: +# - storageClassName: pd-ssd (GKE) / gp3 (EKS) / managed-premium (AKS) +# - replicas: 2+ for microservices +# - resource limits: larger CPU/memory allocations +# - image tags: pinned SHAs instead of :latest +# - TLS: cert-manager ClusterIssuer (Let's Encrypt or internal CA) +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base diff --git a/k8s/scripts/apply.sh b/k8s/scripts/apply.sh new file mode 100755 index 0000000..7efe074 --- /dev/null +++ b/k8s/scripts/apply.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +K8S_DIR="${SCRIPT_DIR}/.." +NAMESPACE="eshop-microservices" +OVERLAY="${1:-local}" + +echo "=== EshopMicroservices K8s Deployment ===" +echo "Overlay: $OVERLAY" +echo "" + +if ! kubectl cluster-info &>/dev/null; then + echo "ERROR: kubectl is not connected to a cluster." + echo "For minikube: minikube start" + echo "For Docker Desktop: enable Kubernetes in Docker Desktop settings" + exit 1 +fi + +echo "=== Ensuring namespace exists ===" +kubectl apply -f "${K8S_DIR}/base/00-core/namespace.yaml" +echo "" + +if ! kubectl get secret cert-catalog-api -n "$NAMESPACE" &>/dev/null; then + echo "Cert secrets not found. Running create-cert-secrets.sh..." + echo "" + bash "${SCRIPT_DIR}/create-cert-secrets.sh" + echo "" +fi + +echo "=== Applying overlay: $OVERLAY ===" +kubectl apply -k "${K8S_DIR}/overlays/${OVERLAY}" + +echo "" +echo "=== Deployment complete ===" +echo "Watch rollout: kubectl get pods -n $NAMESPACE -w" +echo "Check status: kubectl get all -n $NAMESPACE" diff --git a/k8s/scripts/create-cert-secrets.sh b/k8s/scripts/create-cert-secrets.sh new file mode 100755 index 0000000..4626883 --- /dev/null +++ b/k8s/scripts/create-cert-secrets.sh @@ -0,0 +1,74 @@ +#!/bin/bash +set -e + +NAMESPACE="eshop-microservices" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +CERTS_DIR="${SCRIPT_DIR}/../base/00-core/certs" + +if [ ! -d "$CERTS_DIR" ]; then + echo "ERROR: $CERTS_DIR not found." + echo "Run: mkdir -p k8s/base/00-core/certs && cd src/certificates && ./generate-certs.sh" + exit 1 +fi + +check_cert() { + local file="$CERTS_DIR/$1" + if [ ! -f "$file" ]; then + echo "ERROR: Missing cert file: $file" + echo "Run: cd src/certificates && ./generate-certs.sh" + exit 1 + fi +} + +check_cert "catalog.pfx" +check_cert "basket.pfx" +check_cert "discount.pfx" +check_cert "identity.pfx" +check_cert "order-command-api.pfx" +check_cert "order-query-event-api.pfx" +check_cert "order-query-event-processor.pfx" +check_cert "api-gateway.pfx" +check_cert "ca.crt" +check_cert "eshop-local.crt" +check_cert "eshop-local.key" + +echo "=== Creating cert Secrets in namespace: $NAMESPACE ===" + +create_cert_secret() { + local SECRET_NAME="$1" + local PFX_KEY="$2" + local PFX_FILE="$CERTS_DIR/$3" + + kubectl create secret generic "$SECRET_NAME" \ + --from-file="${PFX_KEY}=${PFX_FILE}" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - + echo " ✓ $SECRET_NAME" +} + +create_cert_secret "cert-catalog-api" "catalog.pfx" "catalog.pfx" +create_cert_secret "cert-basket-api" "basket.pfx" "basket.pfx" +create_cert_secret "cert-discount-grpc" "discount.pfx" "discount.pfx" +create_cert_secret "cert-identity-api" "identity.pfx" "identity.pfx" +create_cert_secret "cert-order-command-api" "order-command-api.pfx" "order-command-api.pfx" +create_cert_secret "cert-order-query-api" "order-query-event-api.pfx" "order-query-event-api.pfx" +create_cert_secret "cert-order-query-eventprocessor" "order-query-event-processor.pfx" "order-query-event-processor.pfx" +create_cert_secret "cert-api-gateway" "api-gateway.pfx" "api-gateway.pfx" + +echo "=== Creating ingress TLS secret ===" +kubectl create secret tls ingress-tls \ + --cert="${CERTS_DIR}/eshop-local.crt" \ + --key="${CERTS_DIR}/eshop-local.key" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - +echo " ✓ ingress-tls" + +echo "=== Creating CA ConfigMap ===" +kubectl create configmap cert-ca \ + --from-file="ca.crt=${CERTS_DIR}/ca.crt" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - +echo " ✓ cert-ca (ConfigMap)" + +echo "" +echo "=== All cert secrets created successfully ===" diff --git a/k8s/scripts/hosts-setup.sh b/k8s/scripts/hosts-setup.sh new file mode 100755 index 0000000..70d9bbe --- /dev/null +++ b/k8s/scripts/hosts-setup.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Prints /etc/hosts entries needed for *.eshop.local ingress rules. + +detect_ip() { + if command -v minikube &>/dev/null && minikube status &>/dev/null 2>&1; then + minikube ip + return + fi + + # Docker Desktop maps the ingress LoadBalancer to localhost — its internal VM IP + # (198.19.249.x) is not routable from Electron-based apps like Postman. + local KUBE_CONTEXT + KUBE_CONTEXT=$(kubectl config current-context 2>/dev/null) + if [ "$KUBE_CONTEXT" = "docker-desktop" ]; then + echo "127.0.0.1" + return + fi + + local LB_IP + LB_IP=$(kubectl get svc ingress-nginx-controller -n ingress-nginx \ + -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null) + if [ -n "$LB_IP" ] && [ "$LB_IP" != "null" ]; then + echo "$LB_IP" + return + fi + + echo "127.0.0.1" +} + +INGRESS_IP=$(detect_ip) + +echo "# EshopMicroservices — add these to /etc/hosts" +echo "# Detected ingress IP: $INGRESS_IP" +echo "" +echo "$INGRESS_IP api.eshop.local" +echo "$INGRESS_IP identity.eshop.local" +echo "$INGRESS_IP mailpit.eshop.local" +echo "$INGRESS_IP kibana.eshop.local" +echo "$INGRESS_IP jaeger.eshop.local" +echo "$INGRESS_IP grafana.eshop.local" +echo "$INGRESS_IP prometheus.eshop.local" +echo "$INGRESS_IP rabbitmq.eshop.local" diff --git a/k8s/scripts/teardown.sh b/k8s/scripts/teardown.sh new file mode 100755 index 0000000..57e7a8e --- /dev/null +++ b/k8s/scripts/teardown.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +K8S_DIR="${SCRIPT_DIR}/.." +NAMESPACE="eshop-microservices" +OVERLAY="${1:-local}" + +echo "=== EshopMicroservices K8s Teardown ===" +echo "Overlay: $OVERLAY" +echo "" + +if ! kubectl cluster-info &>/dev/null; then + echo "ERROR: kubectl is not connected to a cluster." + exit 1 +fi + +kubectl delete -k "${K8S_DIR}/overlays/${OVERLAY}" --ignore-not-found + +if [[ "${2}" == "--wipe-data" ]]; then + echo "" + echo "=== Deleting PVCs (--wipe-data flag set) ===" + kubectl delete pvc --all -n "$NAMESPACE" --ignore-not-found + echo "All PVCs deleted." +fi + +echo "" +echo "=== Teardown complete ===" +echo "To redeploy: bash k8s/scripts/apply.sh $OVERLAY" diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index db8bee3..83408f7 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -79,6 +79,7 @@ + diff --git a/src/Services/Identity/Identity.API.Tests/IntegrationTests/DataProtectionKeyPersistenceTests.cs b/src/Services/Identity/Identity.API.Tests/IntegrationTests/DataProtectionKeyPersistenceTests.cs new file mode 100644 index 0000000..15244d4 --- /dev/null +++ b/src/Services/Identity/Identity.API.Tests/IntegrationTests/DataProtectionKeyPersistenceTests.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore; + +namespace Identity.API.Tests.IntegrationTests; + +[Collection(IntegrationTestCollection.Name)] +public class DataProtectionKeyPersistenceTests(IdentityApiSpecification specification) +{ + /// + /// A GET to the login page triggers antiforgery token creation, which forces Data Protection to generate and persist a key + /// + [Fact] + public async Task DataProtection_keys_are_persisted_to_database_after_first_request() + { + var client = specification._factory!.CreateClient(); + await client.GetAsync("/Account/Login"); + + await using var scope = specification._factory!.Services.CreateAsyncScope(); + var db = scope.ServiceProvider.GetRequiredService(); + var keyCount = await db.DataProtectionKeys.CountAsync(); + keyCount.ShouldBeGreaterThan(0); + } +} diff --git a/src/Services/Identity/Identity.API.Tests/UnitTests/ApplicationDbContextTests.cs b/src/Services/Identity/Identity.API.Tests/UnitTests/ApplicationDbContextTests.cs new file mode 100644 index 0000000..ce791a4 --- /dev/null +++ b/src/Services/Identity/Identity.API.Tests/UnitTests/ApplicationDbContextTests.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; + +namespace Identity.API.Tests.UnitTests; + +public class ApplicationDbContextTests +{ + [Fact] + public void ApplicationDbContext_implements_IDataProtectionKeyContext() + { + typeof(IDataProtectionKeyContext) + .IsAssignableFrom(typeof(ApplicationDbContext)) + .ShouldBeTrue(); + } +} diff --git a/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs b/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs index 6919056..2c86dd9 100644 --- a/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs +++ b/src/Services/Identity/Identity.API/Data/ApplicationDbContext.cs @@ -1,16 +1,18 @@ using Identity.API.Models; +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace Identity.API.Data; -public class ApplicationDbContext : IdentityDbContext +public class ApplicationDbContext : IdentityDbContext, IDataProtectionKeyContext { public ApplicationDbContext(DbContextOptions options) : base(options) { } + public DbSet DataProtectionKeys { get; set; } public DbSet VerificationCodes { get; set; } protected override void OnModelCreating(ModelBuilder builder) @@ -20,8 +22,7 @@ protected override void OnModelCreating(ModelBuilder builder) .WithMany(x => x.EmailVerifications) .HasForeignKey(cc => cc.UserId) .OnDelete(DeleteBehavior.Cascade); - - base.OnModelCreating( - builder); + + base.OnModelCreating(builder); } -} \ No newline at end of file +} diff --git a/src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs index bc565e1..88a7046 100644 --- a/src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Services/Identity/Identity.API/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -167,6 +167,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); + modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("FriendlyName") + .HasColumnType("text"); + + b.Property("Xml") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DataProtectionKeys"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { b.Property("Id") diff --git a/src/Services/Identity/Identity.API/HostingExtensions.cs b/src/Services/Identity/Identity.API/HostingExtensions.cs index 46a281d..19b8669 100644 --- a/src/Services/Identity/Identity.API/HostingExtensions.cs +++ b/src/Services/Identity/Identity.API/HostingExtensions.cs @@ -1,5 +1,6 @@ using System.Threading.RateLimiting; using Duende.IdentityServer; +using Microsoft.AspNetCore.DataProtection; using Duende.IdentityServer.Services; using Identity.API.ApiClients.Mailtrap; using Identity.API.Data; @@ -53,6 +54,10 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("IdentityDB"))); + builder.Services.AddDataProtection() + .SetApplicationName("identity-api") + .PersistKeysToDbContext(); + builder.Services.AddMigration(); builder.Services.AddIdentity() diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index 312c4cf..a4c80ef 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Services/Identity/Identity.API/Migrations/20260624110240_AddDataProtectionKeys.Designer.cs b/src/Services/Identity/Identity.API/Migrations/20260624110240_AddDataProtectionKeys.Designer.cs new file mode 100644 index 0000000..500ffbf --- /dev/null +++ b/src/Services/Identity/Identity.API/Migrations/20260624110240_AddDataProtectionKeys.Designer.cs @@ -0,0 +1,393 @@ +// +using System; +using Identity.API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Identity.API.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20260624110240_AddDataProtectionKeys")] + partial class AddDataProtectionKeys + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Identity.API.Data.VerificationCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsActivated") + .HasColumnType("boolean"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("UserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("VerificationCodes"); + }); + + modelBuilder.Entity("Identity.API.Models.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("CardHolderName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CardNumber") + .HasMaxLength(19) + .HasColumnType("character varying(19)"); + + b.Property("CardType") + .HasColumnType("integer"); + + b.Property("City") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("Expiration") + .HasMaxLength(7) + .HasColumnType("character varying(7)"); + + b.Property("LastName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityNumber") + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("State") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Street") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ZipCode") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("FriendlyName") + .HasColumnType("text"); + + b.Property("Xml") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DataProtectionKeys"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Identity.API.Data.VerificationCode", b => + { + b.HasOne("Identity.API.Models.ApplicationUser", "User") + .WithMany("EmailVerifications") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Identity.API.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Identity.API.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Identity.API.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Identity.API.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Identity.API.Models.ApplicationUser", b => + { + b.Navigation("EmailVerifications"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/Identity/Identity.API/Migrations/20260624110240_AddDataProtectionKeys.cs b/src/Services/Identity/Identity.API/Migrations/20260624110240_AddDataProtectionKeys.cs new file mode 100644 index 0000000..9354fcf --- /dev/null +++ b/src/Services/Identity/Identity.API/Migrations/20260624110240_AddDataProtectionKeys.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Identity.API.Migrations +{ + /// + public partial class AddDataProtectionKeys : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DataProtectionKeys", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + FriendlyName = table.Column(type: "text", nullable: true), + Xml = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DataProtectionKeys", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DataProtectionKeys"); + } + } +} diff --git a/src/Services/Identity/Identity.API/Properties/launchSettings.json b/src/Services/Identity/Identity.API/Properties/launchSettings.json index b286b57..30b4ee1 100644 --- a/src/Services/Identity/Identity.API/Properties/launchSettings.json +++ b/src/Services/Identity/Identity.API/Properties/launchSettings.json @@ -1,6 +1,7 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "SelfHost": { + "https": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { @@ -9,4 +10,4 @@ "applicationUrl": "https://localhost:5007" } } -} \ No newline at end of file +} diff --git "a/src/Services/Order.Command/Order.Command.Application/Data/IApplicationDbContext\342\200\216.cs" "b/src/Services/Order.Command/Order.Command.Application/Data/IApplicationDbContext\342\200\216.cs" index ab4fca5..b6b398a 100644 --- "a/src/Services/Order.Command/Order.Command.Application/Data/IApplicationDbContext\342\200\216.cs" +++ "b/src/Services/Order.Command/Order.Command.Application/Data/IApplicationDbContext\342\200\216.cs" @@ -11,4 +11,4 @@ public interface IApplicationDbContext DatabaseFacade Database { get; } Task SaveChangesAsync(CancellationToken cancellationToken); -} \ No newline at end of file +} diff --git a/src/Services/Order.Query/Order.Query/PostgresConfig/PostgresDbExtension.cs b/src/Services/Order.Query/Order.Query/PostgresConfig/PostgresDbExtension.cs index b22596c..69c2bee 100644 --- a/src/Services/Order.Query/Order.Query/PostgresConfig/PostgresDbExtension.cs +++ b/src/Services/Order.Query/Order.Query/PostgresConfig/PostgresDbExtension.cs @@ -26,7 +26,8 @@ public static IServiceCollection AddPostgresDb(this IServiceCollection services, .Index(x => x.EventType) .Index(x => x.CreatedAt) .UniqueIndex(x => x.Id); - }).UseLightweightSessions(); + }).UseLightweightSessions() + .ApplyAllDatabaseChangesOnStartup(); return services; } } \ No newline at end of file diff --git a/src/certificates/api-gateway.crt b/src/certificates/api-gateway.crt index 36c5a2e..728849a 100644 --- a/src/certificates/api-gateway.crt +++ b/src/certificates/api-gateway.crt @@ -1,28 +1,28 @@ -----BEGIN CERTIFICATE----- -MIIE1TCCAr2gAwIBAgIUAfT1chDFp31Leol2oRLutw0pcfEwDQYJKoZIhvcNAQEL +MIIE1TCCAr2gAwIBAgIUAfT1chDFp31Leol2oRLutw0pchIwDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM3WhcNMjcw -MzE2MTA0MjM3WjAWMRQwEgYDVQQDDAthcGktZ2F0ZXdheTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAJjamTV8adtFKRxL3jx7Wd3Yacpwk+YpIkW4xkO7 -SEZBwyd1hWLiKoBf73elFQPjvx/Df0iD+TyKQIq5kohVO7HaV0zPQEZ0YsxXYfOh -uRSISMz0DvLR5tKFr3OmDCZbMhmdfYNQk/mSIXyqzbKxKSgprnKfq4KchEAzxYya -oL5l4I5SfSeHTd6fW0ILt6CiJjysvoEe4wxA4+3R1pR4RBjQLjJbfr2N6VVZ21UB -loyuTHhi0ltoeyqGxqwxkFbTczCBo0fGx6LX1At29Vm9r4roDbbJVmVR02XlxCbe -wg4otN1QEjz/bN6PCprrwEKslvihApbdhL4nVaEv42njbUsCAwEAAaOB6jCB5zCB +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQzWhcNMjcw +NjIzMTEzOTQzWjAWMRQwEgYDVQQDDAthcGktZ2F0ZXdheTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANcuO413iikFBCyvyRfjis/2oQ+3LwjEwBfsiF/u +n+tSimUEhEW7cSn5OQ9jV5+wSXHAWBEqBejUdgTaCVdq6G2tlu7y3ZTH3PqO6yms +3T7dqw+bXffO2MbYOVn5TWLQzZqKg4nm/sKR9gY9gktfVZSGOhG31Fee756NXpgb +JpV8RsTO6TNJGncX42PUQcoUXcgk9XRUTPhJyFzZ8Jtdz0P5hwMOIHOU1Ns7hat8 +B85YmCWeLACx+s1lpLLciClMKos4qTpBGdBpHhLzypjEvIfY9MRjfDm4r4jg9J++ +RML3JJnTD1G1NDw/kbaoXQqtHVGv5wDqYFAaU+aDP32fwKkCAwEAAaOB6jCB5zCB ggYDVR0RBHsweYILYXBpLmdhdGV3YXmCC2FwaS1nYXRld2F5gh9hcGktZ2F0ZXdh eS5lc2hvcC1taWNyb3NlcnZpY2VzgjFhcGktZ2F0ZXdheS5lc2hvcC1taWNyb3Nl cnZpY2VzLnN2Yy5jbHVzdGVyLmxvY2Fsgglsb2NhbGhvc3QwCwYDVR0PBAQDAgWg -MBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBQd4nOqsvPC4oDu0xWpXDBL -0GGxYzAfBgNVHSMEGDAWgBTx56zBqYwcdVZrGp5PFuPgViXGATANBgkqhkiG9w0B -AQsFAAOCAgEAJpSlOx9/FYBO6TjbOXMN6dgHgnxqCX0mDWPEDOf8Rz8CyJ23ZJql -iA+pkM6jAkY5Q0SAY7XwNjydI52EIhbvN6v7nMhPwH3vPLdpCll9eHrJTmRfWyGr -AAyzMLZq4+cPLsfftraAC6N8A8Yv1xwbh5p9AxXeYCjvxESCBh13ql9bgoBuGEOP -eKoAjZOU2LYxNocggUCehSBjQ0A4KxLC8W/HQAufj5S5HH0yT2d1mDUGnb7ui6K+ -KDzx6ZmzbxMXLtXGTlJZr3FFB9uG16i1NMHyrRnPoNPP3lxqt+HskVyGDXKyQ+3F -8ryPcHulEDqZBeaTIQO01C2MclxR2Kk3maMX0ZeJzGAt+lbMwjk2aF79xDsvfTA6 -RFvw7PLV27Rs+KlawWn4qBhV99enT2IBWwYslLOowN2BaV2o+V8QDROilkpLFWPV -M+kkwSZs9YI6ZM7Vr98T36MiQNxFko+phF1XGvOp2HZoFPpLVxmUt5MJdc+3kHAR -bsYbZU+hpjGQyUO7N9O4uhh82ChcV/YLONj4ZUFBsa8L9SJYT3VCnXXGI8Mo8nWk -ZSh0cL+cpU3ZukIWmcKYBoma651h3dXzgzUPJX4oiuqvrkrjYYCn0JzXvock6ENH -qPr2RMsoZKjEBjfpOQze8AvwNRjU9HQ8Nr74Rlfe+0FY25wtm0YhnKc= +MBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBSXCLno8eY3GrQCl8idfGUa +CHd2yzAfBgNVHSMEGDAWgBS/Eltye2Mg3kuSyJX4v+CKvSgsCDANBgkqhkiG9w0B +AQsFAAOCAgEAJdEKaRgcAawxFSXKvfQqrP2MPSvpG+Y4Jy7Wn0Mh8zCoAML1EnUa +jBX1/QytZ8APXD+CZlpLGa1Q5+eb6Q3YO1wv1JKJmh4orsjfcU0V6OK7L7Ad3Bl1 +XOnfUYHxJppfCA48hqQOiMSUXzhcSaL0gIGa3T8F4skMiRTwGKPWVA4UFxrDeL1x +MbocXC6KRmFLqKE5KzVi/ffEDmwd4yO/AiTyNgDiffDq/13qyJnrc8M+uSuacYhX +i5MM5Z2o169vs4jwKzbUX/HWx5OS/6Ou9OT0BNK628MgrwFmbblYHZPlqM8XvPXS +sX5VO0VMFuNGfVbgBpA3y/PpbzC/qwiv58kgbcrHiJg0pFkiutdsWcqFmVvTsxU7 ++esELQljIb5WaCvLn0/MAQ8guaugvDQLUb7xbdBF60oAj4fE/rgLa65erHbsEq8f +yQJEhnUiHu+JR3ag/7ETRvY93G9N8H/gtI0BDFxs5B6PcA6HE8zpufde27CvAjG5 +9bEBU0WtVnHu6jhbLheK9jbeQPTLfrjcEWQF0yElamGIUcFI5DH/qwyyJtDwDO5W +d9zOj3vFmpRWJawp+GUJmsJATWE1RLSntzYXFH80xGGN5K72jd13OFGC+unW/lXQ +ePRm4dGl495TYqbl0sDtI3+ZB9MCRSgQ5RRp2YYzWQZTrgsIiotpflg= -----END CERTIFICATE----- diff --git a/src/certificates/api-gateway.key b/src/certificates/api-gateway.key index a245707..aa57810 100644 --- a/src/certificates/api-gateway.key +++ b/src/certificates/api-gateway.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCY2pk1fGnbRSkc -S948e1nd2GnKcJPmKSJFuMZDu0hGQcMndYVi4iqAX+93pRUD478fw39Ig/k8ikCK -uZKIVTux2ldMz0BGdGLMV2HzobkUiEjM9A7y0ebSha9zpgwmWzIZnX2DUJP5kiF8 -qs2ysSkoKa5yn6uCnIRAM8WMmqC+ZeCOUn0nh03en1tCC7egoiY8rL6BHuMMQOPt -0daUeEQY0C4yW369jelVWdtVAZaMrkx4YtJbaHsqhsasMZBW03MwgaNHxsei19QL -dvVZva+K6A22yVZlUdNl5cQm3sIOKLTdUBI8/2zejwqa68BCrJb4oQKW3YS+J1Wh -L+Np421LAgMBAAECggEAMkPkkRWuO+ik6cS7Otl3hoAl3egigtQxDIuES365eD0k -/4Nij09/mYKy3X4AiKxqy/e+kiqwGev+6H+5A7M/s69w+PXIlcKtQLRVpkge9HUS -t69kgQ5soPtMZLQMl8pykcDcJwQm/THEaFpE1Yfz2FzInLIMNSHiTbiYtLGeva2B -kyCKoSLXKuW/SzUmgKnnsTfRkfrvfACg496mvNB1kyAqS8YbHFxDfswcn9vDfH5r -EddHQD1JcLIS0iQ52qWOpcgCE/4uJ4z/MAdGm7G1Y8M+CiglXmNqxpbHIADE6MFe -aXQpmvyoe85H9AYsyEwwXrv7hpoxpZERx2FvWJS1rQKBgQDR8TihqKHUR17eeuMi -Z9eeB7IbbExCKSx3KzpMv+RJQxD7jbglv7F8l2C2j1QG/YasDswCZpSFIu4AT2dI -XquNCZe+nl/WM+XMnNCF9uuZluuTrOV5JZsHyr+UKpzSrvxNcOTb3UNczsWrx6oE -TM7sjOO80vg9BVpBneodrRISnQKBgQC6Yy4Qz3HsSv+tCPXUVCYCoalWRXEF5xlt -TnqYWKo2OHpyI/cTI/BrBNtml2gRO+Y8Db1/5Rgr3QSeqXEUVDiuDTl4F432WS0d -rKmTSgnNDImeozdDWCmfgcgtotNOMp6n1LqqyaPxmYDImxTrObLS5disVdOdJKfP -pwiEoxsnBwKBgFVtvwmpQRDMagJGJx7c+pRHtWYLT4ysjHeBk5ufihl1vPdf18sk -keiNAMHI2PxvNdnVu5ZOf6kdaZOeu/xq6Yvel2ztrTnQrHXyabfZnk1FaF8TP91o -PAmTqxlzrZTdt7Ubd0UwaDTfvvgDq19MkfcX7aPshS7veqawx4+D2ZLRAoGAWVDf -qUSPNgk2fge2LZppYIdxaxr5rzdwEtYxn0GVx0fHPV0IsA5fzhjUvlO9lcybZpm6 -/kedDp/p79IIkxJM2vMRYAABklRnbznnROKM0cq5Q+C4wbfEsl/xuhS1p1pQduJU -1TStMEA722WdX58Vl0R3URYLwtjm5XYIee7jOw8CgYA7e/4phZkK3kiamsAkpW+9 -ouzj3dq0Rpv2QrnflhlfGyBygurq5eR+Nc6wNraoZOhBag7esRnjh1gmjRj7f58j -lYn8n4axUiO+NRt8+bVJc1J42/Ussjzgr6JAx3pTdFYqJVCqGrj56UthgsRUJXXW -fi5NAuP7mZ2dKy6S2F+paQ== +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDXLjuNd4opBQQs +r8kX44rP9qEPty8IxMAX7Ihf7p/rUoplBIRFu3Ep+TkPY1efsElxwFgRKgXo1HYE +2glXauhtrZbu8t2Ux9z6jusprN0+3asPm133ztjG2DlZ+U1i0M2aioOJ5v7CkfYG +PYJLX1WUhjoRt9RXnu+ejV6YGyaVfEbEzukzSRp3F+Nj1EHKFF3IJPV0VEz4Schc +2fCbXc9D+YcDDiBzlNTbO4WrfAfOWJglniwAsfrNZaSy3IgpTCqLOKk6QRnQaR4S +88qYxLyH2PTEY3w5uK+I4PSfvkTC9ySZ0w9RtTQ8P5G2qF0KrR1Rr+cA6mBQGlPm +gz99n8CpAgMBAAECggEACmL3f2400Pg7xG9uGL/ZmGJlJwXL2KkXRPWx0IBLdQJc +iUs/mkEVvDWvi36wq6szTwZpNII6MPapGrYD65W5Zz/mOvL7VJ5AHFJlPLNU0PRw +uHW4Al6YPU2Rw8t3m4yM0XKcWP35hUlNM5ho+hE9kjLXdI79H4dIYDdz3d+OTCVR +7Z1E7ji2AelVbSKCsPtJVENcqZgaLKJoqr075BIeEi9MGm+GDF59y/5Zr9/idtz6 +YjSQ7cJhrcoMXOx4uspkP6CQl69TQiFrsJvLYxXL48FsUysplIYEXw2CYOPcrWWa +/CjC0uvkAnMiwDNMAkVfKO2aYYZdBb3rYI0N5VIMfQKBgQD6UGd5Q6NTudWepiXn +mFoLxxIQ2YSaY1xfQr6nmqy0nCPSHVMBjvmJds8U/MeRtntOr/Pqb2Z5vsR/suJP +YWAKaFr4+cjhGv7xt3oxA5uE3wgjwHdx3d24qgpRKIuPg2F07gnMB8MvnbbsW1xv +2qlwECL+FAA+w381jJMSuFvw5QKBgQDcEYZF2VrOv2qOLt3jwstxz33eW1g1yGHf +BmHhwFJpA4+Fbe5jWBjbT+kf3gGyeiAtuJ8Hx+hlYxxF+PGOoMkFZUlzFEVZ5fZL +1bhwTOMA3m/gBrjC0Arha223x3u8zPjIKce9eJhIzFNeEW2kUoucE147Q2B3fynf +2IR2CA2IdQKBgQC/VZxyffgndKJMPbY1nCggXo95n7sThCXEjzFKzhl7iOp8nnun +clFd+Rn7celegT0p/acVqQeMwfxTnDoO8WDHM9NuAwjAwLDltRjKxHYpD46aPXFP +8YactCVkufhLv+JLzfRhKAHTsNt1ObSjr2Hazgrhagpx71+aYBS/t3pX3QKBgQDG +EF+w7fb0rQLSBQxfuSoxvHWkcsHpZffwKmZeMCH7seCyTkaH0vpMKJfAvqb4Y0Ii +5E79Sca3uYPw1iVSIRPLb2Wz1UK1rmsFxczCBfEpDwnRrzsK2wNv7qhJB5kuS6x9 +Ol0zAh7NJljCCR2ND13nkub0n6dq5WBivxQ4xvanIQKBgCVjfvB+gHAbzKFpKSXu +TPwBHpNZj0QnK25yK5UWkMde7/I4j1RMKTJY8hVPIeadX7gxPTUb53wharA6d+ob +MrHdATCn99Z8yLmqLdSZc+qcSa/9uMpoVLuBi3VeY2gOam1U0TypCF7YUKxfYy2J +OC6TgHEyt5kPmOGt9LIYjh1e -----END PRIVATE KEY----- diff --git a/src/certificates/api-gateway.pfx b/src/certificates/api-gateway.pfx index 63856e8..84be39d 100644 Binary files a/src/certificates/api-gateway.pfx and b/src/certificates/api-gateway.pfx differ diff --git a/src/certificates/basket.crt b/src/certificates/basket.crt index 2be2e22..c2fe4e8 100644 --- a/src/certificates/basket.crt +++ b/src/certificates/basket.crt @@ -1,28 +1,28 @@ -----BEGIN CERTIFICATE----- -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 -----END CERTIFICATE----- diff --git a/src/certificates/basket.key b/src/certificates/basket.key index d2668c6..12c57f2 100644 --- a/src/certificates/basket.key +++ b/src/certificates/basket.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6HdS7TwKXrblZ -PpThGLHi+LYzns2s/+2DgJN15Y5G0b1zW6TQAeRlmIbKBVCMarRAhSLZOwbQZgkn -jcAd3+6pGSbzS7yOk2UiPtYqrmEBlFBh5O7mpedr8N7dKKMwWWwpElG7VQ5phiEG -g6hoL9smmOrLIsPlMXNxTc+W7XthQpWGOeqaQwyRSB/8CN/NPe7Vy7/f4/7zc8Pc -uVVEgYPurNSiOWNSJYA4IBOHc0IHDxx7sHlUrgdpCEA0yVg0RlQc1yoWedkKS9Mg -A1XQihcDgeGyTWtv2FAUflKqA0VnTWP7xmvYF0A60vF/aoodxM6rnt1Naq3WAEjq -H2HoGuRBAgMBAAECggEAAn3EO3ahCQE7DioDiajQNsLQA4xgYeyyE/TMZINcXm/P -yqPDJsKjuUVrpnggPiTugT+W+hPrcS4weK5R0ESPWAWdaxvMLBdmfuka6krXwxLm -aY0MMputZ5k7jnfNCWhlBX64h9qpXPm95u2ruytK0m8xE2OFfkOlcTKSsQlAQcrB -xlaPPr6aLSWB3gc6f+ERJIyi6z3gIDLzKkiu5EmQtUF/iKTgDb4YQKWftMk9E2H3 -0Rqm8v3jurqcJzIlZG8ghWQo/c/tCWg+rpUfSeoSsiKurtbVuDpARJNP9vi5r6yA -e7q+nExn7KIMt7D1bCQWuDgjlMIHhMJ1iEY/yLoo3QKBgQDlR2ZuYzmVY3G3pWZf -Vf1072qPZ0M6/icpPEPbtvG6mUzGorBiOXmCt4Fb3RnRMeQlwtx2gN7wCtGIF1i+ -kS+dLWreKi4BwRMvJKKVesXEEpHBNGVrMju4g568pNudNGx782bpPDrii5srYg28 -Hwv39qVFuYEgzkROoNllFLIlVQKBgQDPzqtV5c8yh0zPV0Nu2ijnvJFZXJmnjo5g -VxwzA4r5BoX616e709TraXTPnvwGgGGMjRBnBqIDaqm7Ka6WHKBk7Z6GJj8w2c8x -tiCpRT8TVhbrTRgPsGD9K5aLy+cLqosQrJoRJp3sl6kwocw/Q/QLzSoXt6DOiFxk -4PAs1lgDPQKBgC5jv+nd0azULhIGOSxY7atXNaxGLGgnPC0vsFsoLMigc9RM3ntB -PcCg+F9p4OteuNabEpg3guP2jGaIsr/8CDI5GkJRLnXUZtlHBE5SROljCHKa81o5 -E7RFjTyF7plkHf8GRHA0a4Wi0YZ5lGXXskg9czskSWgl09RE3zeAdHrxAoGATE82 -N6rWNVXd7N28k35lOwPR1CDfA9qjidkzL8CDTgMJPB3pKF4XeAMXtA5Lug92wugi -N9MFt395qJMb21/TvnxLlDODTOsO3NBmmgIlsXIRpIKA7XH1i8Jv3BIaW/xaaNsZ -EGc/4tumc4dWu3y2p4bFiEQUNwN3+ktnpu9nDnkCgYBMcib7zewkAh2mu/IhE/9u -oMV3NEsmOLrtPrhiFz5b6rv1yT+rkn6OYiKGglu0NZl+JQdMUc6NibdQKSb/o5qa -o75yrZbWetTcbvOwdFfVBCxH6GEIMbikK9vzQ2Q/NYojaSOaKJuNntuNltkuXyMV -q67NA/42DvFK8mic2N4hHQ== +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/Mf8TQCj8Nuo/ +CgEJe62TeWOZv9wQTGpiN8L8cwv2If8RVBrguUTvzaHLwwq4S3TaNK+A/j7XvP9w +/cJLESRaJkfNFAUwTGxvQwa9/a72Iyg/GMIhs2+ElG9ss/RSJIlsSnNqKSwowTvG +Wo8vybH4+ttPJda3eZ28wl1Bk4gk5SfS6mp7MSEaiFYfTlka+VhvosVYINCeIoLV +WoBJf22GxgtDpQMyIJFO4SVHr5q+YFDQIaAZnC3V8sv4kVnxJp8zs2PKUZi14xCZ +nVOfXI7kkA2Y4qbNk0Jt+69Xz40KpQz0RGxIv55FAmOzTcBHmDXLOddt3psOuBWP +p9sPV3cjAgMBAAECggEAARquUPOlaPN+Pdf2cpISyg/A6gHoKPXwBVoyF5gogQbo +PLbiItsfEU18OjuJo8/XwGzeeJ2/SiquxP3KMfnK3nRrJL2RXBqM48Wc09sTuBsy +385qTJyHL9pVnGibqB/K5WO2r+3F8gRPrpEWU53UF86HFrluuIeMyCrNNBRAjIn9 +tvFnc++nl0hFHvFOb+IvlYhV5eLUbIVD/veB0FoeavKR14QsuTq4/dM3tFQSQFSZ +fYKjAL34w1Lh7of/caLS4B4nDuRMDomlOe9T1lyX3NDoVWJINNfbzuEbU0KXyV1D +Qg9bwPtEP7mdINaK63wYMx3pfgbf1owSFlZA3sKNTQKBgQDjUIr+K7/wqj/oO9Zd +ICPW1BbRB0ugd53HMf97bUiRGClcfytXJs79OrDZwNxRjN1vPG2PmAo+3TUcFT6O +Ms2dkOwSA7/CZOPrzXNo3OAgRXPvRa0S1tSnyfBWWz6bqb2COOWk+8ASJiAyhkgz +LAzC0pwflXT2vi4SQHuJyYC2VQKBgQDXUpwG9xrvjR88tYabeI1/F7ZGATUFTZ5s +WPRcixjrRFkwkbzOmmdpGR6wnEg9wwc6yAjwH4QQlujNB45U8+/TWFxWJFe0nEX7 +fFFMs/3NX1mQxRjFl1Wqtl0MT3mTu4CnQjld5dcl/zASbzBTQsN2NcAjbUz8+FYu +Ufx+lFk/lwKBgGhpe56qS9zo5rfunFVkSPIJs31KI5POvdtcfOSd2wJCneUNyMOc +YOFyTv+Gleyjjqbkk9KsXLBpfVar73LzpPymL7lKnY9WNlb+pO9a3VwVat5SG+CW +a1Gy8UFJYiWwPwsMxXcV6DCt8IYkpg9TQX1PrkTXqsUXsCPUGKq+su+NAoGADrPi +WYtn+HF/b4rJnTYXG1WIKbGNaEZLigRs8yDAW9g36twYs1bRtthzQwX43NbDWJ0u +Fw9f2i4jyVQ5wM1DVAAVlgA3SOre0HRFrOIhc3OOTxdWQK+7tsNrCRsoJxFHkKQx +/JpkHYEWTDvxZc4KQLkc3I5rEl72q4UHo7EHgxMCgYEAzEXtf4mp0L+p0gKuIL52 +KPHhvcxykO/FhPVVLw9CXcOgd/d70Vpfu+1cEEfZtCT9n9oYon/8zEFVa/6xvRtw +7OvTwFzV7LKgTVQ+H+lCkZCgfBQB62JB2Mx6qOA544qS4LDH1R3Cvo4gr2yYp9Q2 +mElm/Kv6eJ7cBbUqlEmAXEQ= -----END PRIVATE KEY----- diff --git a/src/certificates/basket.pfx b/src/certificates/basket.pfx index 47d4fd4..66af2e7 100644 Binary files a/src/certificates/basket.pfx and b/src/certificates/basket.pfx differ diff --git a/src/certificates/ca.crt b/src/certificates/ca.crt index 91ae2b2..50d7dca 100644 --- a/src/certificates/ca.crt +++ b/src/certificates/ca.crt @@ -1,32 +1,32 @@ -----BEGIN CERTIFICATE----- -MIIFbTCCA1WgAwIBAgIUMSNXy7CiBYeMGexQzSIkwq0iy4gwDQYJKoZIhvcNAQEL +MIIFbTCCA1WgAwIBAgIUayRF3jfDuAhtY3C9AHhL7TsgDm8wDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM2WhcNMjcw -MzE2MTA0MjM2WjBGMScwJQYDVQQDDB5Fc2hvcE1pY3Jvc2VydmljZXMgSW50ZXJu +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQyWhcNMjcw +NjIzMTEzOTQyWjBGMScwJQYDVQQDDB5Fc2hvcE1pY3Jvc2VydmljZXMgSW50ZXJu YWwgQ0ExGzAZBgNVBAoMEkVzaG9wTWljcm9zZXJ2aWNlczCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAKejs4MkvQiP7Ae+VqYm3rXlM68qA92+D+8Ov3za -VMf3ZweK6xg/HEuD7vbJU9AQ5L8lRaSiSePa/mwvXgvudZE3zpHintEofc/9gsL5 -mHDr2sMhm8b24Ad1bRo//S18aDOY017GJ5LntniFBqqI0cxE9u+STq55JhiRBy9u -DHrXFPvB8wC7nQ2GRiOMdAz5rpg6ao7VOiYI0UIiKrGKFGNP61859YLH7hEvv4S2 -B9rxYIc5TcsQDe4+da4Gl5KcFtr3hHRNQXJtxHXvKuE/0PNp656XyWQY4Mb9Ze9h -bR/xXOCkoTLooXSCjqRdf3IVL/f3BChdgB8DNWYwvTyyHIAGbolkKj/QyE8/RG12 -qw0AZkRdublb51qV9WajzVEMF1P7Bkhj0ZoMN40w95SHgkPUmoZoPbPiJz+ylDKi -kbyIE/ROYDKZ8nkNenaFxkdcuSIEgJw7E9pNbNYILNKl6o4JC21QGUBcwRi9ahpJ -HOOGZSvRbUN/U/vSaq5UR498mzhooe8HT4TEoKxMRDCA092tkrNen7ceckB4Xf0s -ud+wIYFNGrEj7LZGp3WdYZ0bUL/5Unlci1lycCvXbUQX40paHUbO8Uzfj7Y1z4ev -Wl+Wpw6RKchkYUFzpibhQfJjaOzaQs3XB2tNkeTRGWuZy/0elC34mQocFw8VUEgw -4AQZAgMBAAGjUzBRMB0GA1UdDgQWBBTx56zBqYwcdVZrGp5PFuPgViXGATAfBgNV -HSMEGDAWgBTx56zBqYwcdVZrGp5PFuPgViXGATAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBCwUAA4ICAQCOOe7qoBszpzilUskWUlL6UJwYrqL+n+k4EYgJAGdR -KyrFgjk/TpWJy+/JJc3kg3ABGUZgnX6lJmzivyZHH3cjjz3zycmFIrXJZnbaDM70 -mveGAoTEfhr2gydYkwHsaspRKsLgwuXmsuzHnQ2ULmIjfL78T3V5XY/TnT/xhDeI -/9wpeq3IzeLCRQB4OdmoUDtRYK4JGBmODND7G5IDGmZgXM/MpyfIp1fqK05KQaMu -swCTwF/fp869/VfCYgT08lJssi2PfZR5Gu2e619a4EpBrpU6qEmYAKrhkRacifh1 -pTXETJaMEym3ClFRIs12Rakz0tQwbW6CvcUW+6KlKzHlHCXi38HrSS1zlhHwNB2p -hdFI8PZHOE/DAhzZyy7+4kKYuNxc4zo6+76Xi1k2LH8pkibQWNcjeoEV+Uc77fpT -FxXPv82CCW4hxBhUPB3Oq/kyTaKZEir0g+86q9UVHEan1caemHPo2CJ3QOGv4pdD -t6liE9nmlyRqdwhI6UkdFsYuGcRY3f5Fj+ZQJtskHqZFGPtzi20gJFI3njwoL6eV -D9RAs3Dzmw0U+ZDhl9ydN0oFqVKvmyXHXG+EeFKxKZQj97I5EDbg1DEEzqVm3KMs -vzBnRDRrn2UEwAswh/ESFUJaDSd9i0O1T7Vncj1JImhALyAk5Pq5dpBAYZO6A430 -oA== +AQEBBQADggIPADCCAgoCggIBALtQi1DHcHumrAxqgxKSqG54rHS+v6ZJtdEPVAga +r/0K3iHr40rg0W3FLE0B4aQrlEGZmgV54b7Vymkwvo1hqrEmCgkb684t61KjsOyW +pKHE1KFrQr6ZKm6pQC6AjsAyOYnxf06IAFi3xzobIx4f+mrmcmrI8xe+4SpeO0us +xPmHnU5AnD2Kvzah3DUtctdjsfzkCWh2PlRk7rMH2T4rQMnELSgoHvhS2ycdIkqx +AmT2ETiN5Tdk1JvHoWZRNXeBK3ITlEEt6bwQhzA4eOZkOG61ZP4EOi4sZvBxc/rK +rwYoEUUYjVDdOz0SR1lPQpPbafH6G8VMpvV5OKTcdom2Fg/wG6I/IjWO1QBq09Jc +MBYeVGpGPDwvdKLvY2uDVPjsQ3cbPCeSL6wSkfWpIq5GJDOsv/fe1fIsi8plbG42 +tX/0jOaBdGUgLMfoSKRtKlXz/2vdGl7EsPH5mYJcSkOaUQERanjq9BYt3VrUMBu5 +p0jVqO3ISBsEfx5ryE7dnJWcGxr3XA+/o5+HsIZ/52aRxmk80p0/Tm37vZFcBqNV +KiSO85ZAwBCEFUnpeieqXB4SkZlsaKeerUhkyWYgFPNV5FI//NWoSeA3Tp9c/BNm +tfvLjIwJ4M71+ASgszRBnnhXXquwYauVzZraL7N07g6DCvPY3R5Kh3CKPBp33OIl +Ki3xAgMBAAGjUzBRMB0GA1UdDgQWBBS/Eltye2Mg3kuSyJX4v+CKvSgsCDAfBgNV +HSMEGDAWgBS/Eltye2Mg3kuSyJX4v+CKvSgsCDAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4ICAQAIc/NrPb6vtf4lpE5/+DQO+a1eFvUYXKFHAz4eN9mt +crkGyEoer/Hw3UHtz/u4vXlzlK21zoDdtl2EioAQlnYNq5ciezhZ0RLUoQfs0nE+ +fZhLepFPuJ64EjlkA8nxkR1+ofx2iPi4IIO5OCSLVenbvzPYg34LxNniXDGrX46S +WYpOrR6NM9OdlQUDsm1SmoIs3mc88go9XxffZNzRSCD4semzUW/GtquJUfTcdKPT +a0ifvTBfB+277m84bPuqoDTlxh9l+y2qfUQKOOyNSvNQxSiuqhY073MxTVQAFfM5 +3qg7IJhH71JJ6ioxpabP3GNQk2dq3X/kqah8+vksuzNZVHmLwdDRLu+S4XfnE57n +mfeGG3IwcD+NHYitwdFAFGFvCOO8hklCyiBgpld0RcxPcmyvfEb1iG7oUmVwUMcG +Bg5ohwrIFEodqCEgmQYm/krAsdzVraSK7aMooW9Pp4gsPkqokrEE+Ij4zXOz7v3F +yd7wYwTimMO0nD+lPEGdsa4CZifeOHgKdYNX/+IG3/v2gw9Z9MPd2LV+JHxsan1W +LesM6GlReimwezZecoVpmpsboNB+qLuz8LOO6jXAXWOG4StX583KJJqaJ2Y0ipvf +wRebshQ4QLzIi3qr8rq+lTtSutoMwSCZScrS3xi/3sSyUlaYSq+NAgsIPEdCStiH +bw== -----END CERTIFICATE----- diff --git a/src/certificates/ca.key b/src/certificates/ca.key index 894ce94..5a7f184 100644 --- a/src/certificates/ca.key +++ b/src/certificates/ca.key @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -n7OJGXkkEKDZDlhQitNTsiDNICKa +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 +dRp03p3okPa8byugvgS1FgriAdMcNA== -----END PRIVATE KEY----- diff --git a/src/certificates/ca.srl b/src/certificates/ca.srl index 490a59c..70a2c77 100644 --- a/src/certificates/ca.srl +++ b/src/certificates/ca.srl @@ -1 +1 @@ -01F4F57210C5A77D4B7A8976A112EEB70D2971F1 +01F4F57210C5A77D4B7A8976A112EEB70D297213 diff --git a/src/certificates/catalog.crt b/src/certificates/catalog.crt index 64b618c..a2c41aa 100644 --- a/src/certificates/catalog.crt +++ b/src/certificates/catalog.crt @@ -1,28 +1,28 @@ -----BEGIN CERTIFICATE----- -MIIE0TCCArmgAwIBAgIUAfT1chDFp31Leol2oRLutw0pceowDQYJKoZIhvcNAQEL +MIIE0TCCArmgAwIBAgIUAfT1chDFp31Leol2oRLutw0pcgswDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM2WhcNMjcw -MzE2MTA0MjM2WjASMRAwDgYDVQQDDAdjYXRhbG9nMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAn/NPT6n1lRGaFjEKfmvZwpu/4hfN/8QG6ZYe+ZrkOkHr -NiDgHw6gvURCUwz0kGU98b9Q29iHId19XDE1R2dij84hp3e/med7dDBw1ltTnYg8 -+mvnCz0KR31zEbllwHB6F++TOYWJ8nQRRmS17N1p7WGQWwSdxxAFnnl7VLcFbWnv -1yDvxrLDJErqYRHyRjfJnixdObJcd5gWg80qI/IUHwcveZPDNzCGsaUYXIN6oNyS -NrmKEUgUIonXf3CC+AcXpi1Wb5RWH4fg/iLPOgoxZ4U47a+jdRXwY74kKpY5llg6 -9Vf32SvMNeB+KPb8InuymcUnT6KxcIphdHFGWH2lMwIDAQABo4HqMIHnMIGCBgNV +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQyWhcNMjcw +NjIzMTEzOTQyWjASMRAwDgYDVQQDDAdjYXRhbG9nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA5GpmC9q86V4wN/cKeAqoVOasVWT5Zq24u4fMp49STVk0 +syPXsljuRNyU6cRxIT7OXOOkm+TTfS1gYVAtuOpK5M92K+US2P7e1X15U4l46UvE +qKpp/g02MJ/w5l88UWQWm+zJOK7BsZnR0WiIgVEebE38GrFHGuHkyFGpdGKBmRq/ +h6c3BLKJkVy9zxaL1UMP1xsVBxUe+HdHIFfUz6EPfoTRd3yRopagSiik6ruwUGXx +7jcYbU+5GE7fwwem1S6vaXo0KrL2+mW2iYZGprqcu5wrNEc7EZubqLiZeIoGXZ2g +cGrOm1p7LlM+1CkY/KDsZofqQf8MfHrkkKCEdG/WLQIDAQABo4HqMIHnMIGCBgNV HREEezB5ggtjYXRhbG9nLmFwaYILY2F0YWxvZy1hcGmCH2NhdGFsb2ctYXBpLmVz aG9wLW1pY3Jvc2VydmljZXOCMWNhdGFsb2ctYXBpLmVzaG9wLW1pY3Jvc2Vydmlj ZXMuc3ZjLmNsdXN0ZXIubG9jYWyCCWxvY2FsaG9zdDALBgNVHQ8EBAMCBaAwEwYD -VR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFMKRTWqTkFL9hpiKXVucT0EvLLV/ -MB8GA1UdIwQYMBaAFPHnrMGpjBx1Vmsank8W4+BWJcYBMA0GCSqGSIb3DQEBCwUA -A4ICAQAe/TYtLkNb900rb593CZzTeaAp0VCDHfobWH4CcDDUcygqgsBTpwIbr4x8 -nN6AovjD0yB6DypuQ7BBxluW4R6Sddraot+qkydZ9Be6ZDQlwDWrzfTu8dESYKQJ -/2yfb31mnzE6whHn+uE/HJkkOKyA3vfUTQfh36DHygWMYnnXWRvwpAvjWT/p39Xx -HJSxTxb/cK+i5kYnKsiTnSQBgP/l1yNm9AzAzk7V/Jytj20N/vtmyAhGo0QHOhY0 -zVZeS77B6ZjQwceWOz/Wh1NAP0KP7Fcv5H2F0qEgM6KalUuYHWzcCXb3NOKlXUw6 -8o/8Hf/rSon6ZcYifmOmkPnKMNB1Xh5L4e+2n9c1v8fqbIV+URDtug9FGXo/uGKZ -T7JFkW5Ri0xT27umvGoLcKX7BBU95sTDVJgk8ZOGD0OFuoiWAGahwwAn5UNeJ+44 -ZCxe0Or6rIyKhhcfdA0Q/hud/EUMJAGWtD3z+ynGkDMDqRqCDKVdxeqrLjOxGops -0lJ45UJoe809gPRGIdkBex+occW1gr5TCb1a/nhdKxWy/FjY/ADpGrvimnM1BlG9 -Fyu7k0xxqIlwboFYg0SDrQL9kOZUie774enTFFnmRHh96PNOo/EmMmLWE5tN8IQJ -ywCsZAOz1yZxZStiYDjqt++V1ozX1Ulb/nlMX81DImXS0NTE4A== +VR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFMS8upEfDvGTUE+zuUc3IDkvTFw8 +MB8GA1UdIwQYMBaAFL8SW3J7YyDeS5LIlfi/4Iq9KCwIMA0GCSqGSIb3DQEBCwUA +A4ICAQA2NibBOh5dfvvDaS5zDFzpwkbg9TrYO1A8aZQvTQUd/a7b02GcjMSsZepk +10W/qiT8IE/jSBqejV+fdcMhACZK9czbsyc/n55mIny5i6gotXDcfdjVykmDDwJg +sgjkOrKKldWgMEBmZT51LXEw+R/CjZK38v1UsuoxFqtsRZSOQyq0jRbjUNuzg9iC +OZU6H5uujgw/AznH8HIODRx1aV8P+EewI3ik1pZLTlZ9m1Wo4tfCJqoQ/AdR891E +8dlcr67CJg7DstPR9YN/pAxtzrsc6C229fqasR7Ph77ZZgIlNOggf+Iypf/9s6HD +qIpdnW7ybfeuwqiftxqPWh3v05nsngrMK9BsEFcDQzo+MXKZe16lWFKpaNrGeOGl +Vb4rGvYV6ARRpUcpYuM5tzSVMbmBPQHpVMRgBjZxKv4DhSX7n5uibewxMb7PSV1a +d5+Yz1L61qIRWDF/2kejN+Z34AMIyrgmGkoOK8gfgEXO8w45xpc7Twy+QkUCtmpX +nIMbPMqf1pt0+RhNkwMzZHlj1TtwBnu+UaKczFcyVpbD6YIeHQACRGreVl7HWaQZ +0S/K404KzyM94xRUvZLRu9JgXRPri+BqA1ckzLz4CJ/PZq+1bwLnvy7zmw9+xnoj +2WfVkK2xfun3m0dvrJFm/eSXp/XEk8aWvBQExgKtnMCj4N8aKw== -----END CERTIFICATE----- diff --git a/src/certificates/catalog.key b/src/certificates/catalog.key index 5c90717..f271abc 100644 --- a/src/certificates/catalog.key +++ b/src/certificates/catalog.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCf809PqfWVEZoW -MQp+a9nCm7/iF83/xAbplh75muQ6Qes2IOAfDqC9REJTDPSQZT3xv1Db2Ich3X1c -MTVHZ2KPziGnd7+Z53t0MHDWW1OdiDz6a+cLPQpHfXMRuWXAcHoX75M5hYnydBFG -ZLXs3WntYZBbBJ3HEAWeeXtUtwVtae/XIO/GssMkSuphEfJGN8meLF05slx3mBaD -zSoj8hQfBy95k8M3MIaxpRhcg3qg3JI2uYoRSBQiidd/cIL4BxemLVZvlFYfh+D+ -Is86CjFnhTjtr6N1FfBjviQqljmWWDr1V/fZK8w14H4o9vwie7KZxSdPorFwimF0 -cUZYfaUzAgMBAAECggEAHMYKzvRuos3jT7mrvxlMt6cICjapDqknay7fzJwyEU7Z -bsfUOZIKlXGpksIiXrVvwsTdWWcmzA9JpWOOx5UQFHmK8VLn61pKiZjLO6x7Krwe -6BewHQPyjPDC2f3lkYxKUnL9I5xjt/NsRiMI3R7pltP1wYHfljdKI3uMFa3E8q0S -RzhUXDPkcR9ZXQcH0tk+B/DoDEO9BaTRVdLSOHrwcOZpkaddWnl1hpGX+SmoVU8y -eQzYcmoLZAMzptirugGljNLotHW3vjOJ54dHZlJTYPhCZmbhR2if4COZALHWVOOK -5MM9s1XI2Va06MqHCEDhgRfdmzVdJt+OoUeCZOZACQKBgQDhZ+TvnC4/D2RopDCM -c8jEIxyrEIOIzXUGcEFCOxrtZAN2YqWceEOOM5qbzjo13rb9REirbYFhCy0Akzjc -gP+TQtuSCYOixbPvfxLg1TVz9Dc+1FhQ8JL2PBBkNm1tMTU3496ug+wnDit6m3JP -cTqKYzA6QSt00tSdjsvJVz3RSwKBgQC1qQ6a9JApmRyx6d0iVjdImG5hkJR0PnLc -8nYi7BrebPR9u3XjC1eWa103hUst9YsyxYdovJW6M5FD1x1wiKc5YHQ6IBIxyKa4 -nUuaf6z/ppRrtxmNYO9YxOEnuwheHUl+jO1ZkA/b5N6UlQ3x6Uo9KDtAsrlInm7T -IhXCDBpyuQKBgCgUNiPYzGxQC1WD5FIFAGzHpYBRRmIbzjQf36qsIcSWJPt23OWu -iKyPRm1vxO/xMu5jptw8c2XS++R/SPwEP+1qVOppoKtfpffuy2eI4aFFilE0pqN1 -s1vvICcBeoGQ31qZvO2g7WugXGDHpRK1Gmii7F9fWR/DoSSG0HtzdL1zAoGAUni6 -ybyICmqZrWfn3ePYW1vgmOijjRag3RAyc+5O0HYUlVRa08XdcMuzWTZpiCb2mAk3 -TWR4cT1iELODiQhxKspQWecfe3yFvEClBzI5nyLINRK+RgIhB2LyeTAfP2L6b7qZ -MtUFbiY8qqX028O20YcHR3scRQywcagCysLl6vkCgYAUEeMKmcumM/CjQKKouicB -zLbuYMK5czxjb/s+jWawYYggJAg7aMmFy/SBISbP6SjbXgpgmFdQrjdZwwlOdct7 -gL71qoAVZbONPcBjIhCUJhXNxeL+pfnSrX/58Ueom1EWPut7royK+GyAwjWd0ggt -5jsWrHCqhs5HhaEy2CdynQ== +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkamYL2rzpXjA3 +9wp4CqhU5qxVZPlmrbi7h8ynj1JNWTSzI9eyWO5E3JTpxHEhPs5c46Sb5NN9LWBh +UC246krkz3Yr5RLY/t7VfXlTiXjpS8Soqmn+DTYwn/DmXzxRZBab7Mk4rsGxmdHR +aIiBUR5sTfwasUca4eTIUal0YoGZGr+HpzcEsomRXL3PFovVQw/XGxUHFR74d0cg +V9TPoQ9+hNF3fJGilqBKKKTqu7BQZfHuNxhtT7kYTt/DB6bVLq9pejQqsvb6ZbaJ +hkamupy7nCs0RzsRm5uouJl4igZdnaBwas6bWnsuUz7UKRj8oOxmh+pB/wx8euSQ +oIR0b9YtAgMBAAECggEAJUvOP89Gm2BaxTicR/+Nftdvej4TjxV8nXpOC2oWiTSw +qzOGC8QDm9Dcq9L8me4Uagxtm1rgwYbAPwOFg7UV54iMhhxQWIg9QGTNg7tlt8o8 +YUH6LpZfq87h2evhAHU0T994971pOSOho+zKpTrmmc6eBIm/z37lCWR0I+HVwXbS +qELfJqDXiNU1FIb8DxXIsYDmd3ApXKEFy1o5pxq8B6noxhAxk7JvtNVKk83ENnb6 +Ne53k2QJzFiNKG087TSWaG34mXC94Dxa/VUoAZHejgDGwj5MTrJDdvbtkpBEy6zt +he2RW3Zs1jQBk2Yn+8Ggi/d6TQhDqmK+j8eUXN7vYQKBgQD0IfMnQnuK3SSWH6T/ +SFRdZ9GuV+a8zehAzzftpJYdN22T08txgwrzYMT91f/MnmQKKG/uvDtDNjza2DzU +hJYvdF8+qcmMt52Fz5QOSTU/0WhiZUN7UxvCjhOz3tXeufZ0TUZ4KFYrur8+GJ8Z +Cu/h5heG+jOLjihR4KqH/6nlNQKBgQDvhNzExaLP3ts3XHoflGBQCFT05f9nSnBY +Y0H+PvYbM07TzgMwofk1jasmD96Nr8cuonmwJHIjb2xK5HeVwU7+Y9wWsucWRIv4 +g8fwrLWEV8894ygNChs5XWFA81jVCNR6UjJBCZfoeMwPSr+gQRPP1AyfXOGp3x8j +yq3zWskkGQKBgQCQOaJJdkhAEEc1/Tnfqp5UlCnWoo1oywhDiWfUF+CrH/y3UW8l +/zGv+GJIR22YN5aIPb1qv38PRPKMoyTEtBN5s3k1Lt8oJ62CyNAB5JP1wMO3JXXJ +XJ7QwFi5cZLNwvTrXl+cStAlg2zJxYfwJnry7JjHn/ZlorUFMgHs2EhJZQKBgQDU +bxSXeWqzz0bCzUSLacAae6lOJAfohr8pxa8sXo9NBK6vcJKnuaEcfHAFrCGJrROO +KxCex1RsVVDJA+WEbxUuz0bO4xHOUDGM0uSsc6HypSbsDuLg3cvTjxzIzIxHNjOt +4eUsheOzjh/+mB9pdQ6rT7l6RpjnXztxNTwfELBBUQKBgHXkB0wAo4RsJNjnG/f0 +LxlHvNgWMhRoggWJuEA1F+W72lmEFhc3ULCk8cd2SmeChZ5TVqphCxWJeKXWjQTN +u632Jb/oD7nu37q/oqtk/ya93s3Bbkk19J0+iLz7HBA9yUW9m73rRVGWkcFe2Wgl +YrxbP2G0EzJItaMRmqbvLd9H -----END PRIVATE KEY----- diff --git a/src/certificates/catalog.pfx b/src/certificates/catalog.pfx index c1a515c..8a03141 100644 Binary files a/src/certificates/catalog.pfx and b/src/certificates/catalog.pfx differ diff --git a/src/certificates/discount.crt b/src/certificates/discount.crt index f7f9c54..0d2eb4e 100644 --- a/src/certificates/discount.crt +++ b/src/certificates/discount.crt @@ -1,28 +1,28 @@ -----BEGIN CERTIFICATE----- -MIIE3DCCAsSgAwIBAgIUAfT1chDFp31Leol2oRLutw0pcewwDQYJKoZIhvcNAQEL +MIIE3DCCAsSgAwIBAgIUAfT1chDFp31Leol2oRLutw0pcg0wDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM3WhcNMjcw -MzE2MTA0MjM3WjATMREwDwYDVQQDDAhkaXNjb3VudDCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAOF9DeBM/dMYoljvuqS9jzDXeHrGnNQSaK9q44dn8ugA -B2FogDE3onIzvNLAPeFuuN8REJm47mMI/eqvBLqWwEMMAQ52RF9yxchlD+LrChSq -XT9JIMazssjvQQFZA0D7N2rxlysUnemlmoU3fRAQJxb3yILvyNguQgop7+UNgrse -c0C6wwTd4RiqppofeYIm/ODe9GeW9+7CPPTKa8STmImE558Yqq9+8nBxWML1se8y -plp9QkvIoOMhHaoLSwiSNfqhrCer4bvwjQhM+yZNbtsUhk7DgOsFoJ1QnQ9dHsGN -UStiR43RJ85G8uhaLvsXUgo9xlo60hk6OYVmqzAxaRcCAwEAAaOB9DCB8TCBjAYD +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQyWhcNMjcw +NjIzMTEzOTQyWjATMREwDwYDVQQDDAhkaXNjb3VudDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALeyJp/xuboY/no7r5uAC1lX7LMMQ6kseGT7+EJzQCj/ +Q1/Ow3bg1jy0M6GxJOs7IN3U9oUA5EYMsPrPKx58pCEar6Hxi7RmAAgUtkTB71MQ +gqkmADJa8U7eRP70Pd9WsXOKe3ZrcSqLEYi4n2orERkhR66wiYv/bHI6BzFO1zpY +7fxvMwVbuG//6Vwxqe0j7kjpktUGYIO+OrAccKqxZA5k5407GY6qqOle4eizI88S +mxn4yLljbHqwY7ttydDtINAXeg457wL4Vo33VvJWX27uKBeG7feeD5xWzdUQ8lfe +8J5gEqhjFZ8GrFNQgts7Q6Ma8WFQAEPnpOWGrB2iN7ECAwEAAaOB9DCB8TCBjAYD VR0RBIGEMIGBgg1kaXNjb3VudC5ncnBjgg1kaXNjb3VudC1ncnBjgiFkaXNjb3Vu dC1ncnBjLmVzaG9wLW1pY3Jvc2VydmljZXOCM2Rpc2NvdW50LWdycGMuZXNob3At bWljcm9zZXJ2aWNlcy5zdmMuY2x1c3Rlci5sb2NhbIIJbG9jYWxob3N0MAsGA1Ud -DwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUg1ikGIZRtPZw -kkL2eUyncRu8NPwwHwYDVR0jBBgwFoAU8eeswamMHHVWaxqeTxbj4FYlxgEwDQYJ -KoZIhvcNAQELBQADggIBABZPeC6BwZnbzku7l8tPBO+W511pEkOtaB1efCsSqZdx -Y2HCgXJ/DA23rOHcFncfiQynkFuNKj7Wrf9CCbOv6f22N60MWfjH3k9p9s+9km5B -FgwWB9sPS/jV02DBSeoxM5icHgCAGzyF8QJ5S6gWFivTyqlqV0gOR/AzihAIvn6m -lIaBKm36R3CYGWRhr3q/AaVru9lLcypBdFKe9NO2WYgxYDl9RkN2z+atyBrmjgRI -6hr7DWSrlOVxXQt9E1Mf1eDnQCzRM0hkVpqZdfuDowGdpLQmAelNUupCoUl7GhjW -Ram9Q/zbhh8bKdJt0Kdv3FjK1AUEYFmV7OEsQqkeDuh/kbvPNcBTdBEO5uoLsrPY -e9+lWZjQDk+n+ncOa4UmJd0AxLanCad1kSrlUhYNJ8rPW+Oalt31tO2r+jY3NMCv -YYkv7Qsy5eVYDsMKmuj1jh6+lR1cz33kdJN4yyfcElvS7zJ9qblT1Aa5UA6tyV7r -BTWT5R+cFEkwEVSHbX1qsAqTZwU8KGbtcZi8GThQKjs1nypKguQYPyrlo0NsEaxj -vte3c+5lk5jHmpfHePTSBDwV0ZKCPtIGwt/d7ae+2pOy2thTfUg6OoK75GFe6jOd -2lYPEq/s6vLeY4itx6aWGlkqigKUvQ+7si9C79whxFWWy2YKL9uVDLivyR6s1kiX +DwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUM4tfUpB86Aym +Vbl94tzLZsrZM2UwHwYDVR0jBBgwFoAUvxJbcntjIN5LksiV+L/gir0oLAgwDQYJ +KoZIhvcNAQELBQADggIBALfN5odCV44ud6V+7OXcNdqP0iRO9RCPZc1WRShe7yvj +xJa3YQnt6xkFXOJ0gxqrNI9vWrBvE/s7MkEZpOvFQpHk6/FsDVFMl5esjrD8IvUg +HVx7ItU36TS0wwQ2+5G0VdEP6Bh1BMz86Vh1jhxcfKisywq9ccB3aZu3EUEHkh5l +UiobqHMssJW7t4neUAtoVwl1zHz3lP7CWHR6ehB+UU16OwWUUCUU/NZ0WzpDfMdL +vI3af+TbkO2YUrMgElZf33fjjyHEzPipPey/x8J42ANDnHmCXHiKuXvsg42kGvWs ++yA44ztfEG/rG58/zFsTo72D+rUrn0oAdW8l3Ou/JR3sMP4W/Per8TxmLkXFeeBG +wnYD/lnkXq8BV866oPKKInKvzNGziFtBWU69c4f2nbHczYHJvP03MwHMiMhV/qkY +hIvXbS/gXFAZAUmiQq7gCzsWpjRT2F9lv4lVYhGxxC7MAXIeIRRuSRwl76L9MfqL +GS3zByCeSApwkFWNpRS9WG3QztQqPJBNOwNcfSf31qfB8SQRee8KeG9jwvbpktcn +8p62wkGa06318wV0zEaR7EzgVph7EAHyVJbNf7OWUTWw0BxSLeipHH5bbXXEMvcq +UNBGoPHizu1YBJlaNfv6mUZTQ+QkqssGasOsBSH+8ql65LcX7yvMa/L4WZYRR4SY -----END CERTIFICATE----- diff --git a/src/certificates/discount.key b/src/certificates/discount.key index 495c1e7..925ab05 100644 --- a/src/certificates/discount.key +++ b/src/certificates/discount.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDhfQ3gTP3TGKJY -77qkvY8w13h6xpzUEmivauOHZ/LoAAdhaIAxN6JyM7zSwD3hbrjfERCZuO5jCP3q -rwS6lsBDDAEOdkRfcsXIZQ/i6woUql0/SSDGs7LI70EBWQNA+zdq8ZcrFJ3ppZqF -N30QECcW98iC78jYLkIKKe/lDYK7HnNAusME3eEYqqaaH3mCJvzg3vRnlvfuwjz0 -ymvEk5iJhOefGKqvfvJwcVjC9bHvMqZafUJLyKDjIR2qC0sIkjX6oawnq+G78I0I -TPsmTW7bFIZOw4DrBaCdUJ0PXR7BjVErYkeN0SfORvLoWi77F1IKPcZaOtIZOjmF -ZqswMWkXAgMBAAECggEAEL1cbNtT+Qc6Pv9l30bVUDgG0TKMDP0xRiiMxXSIADiU -U7AGDq4fKK3cZdbwurSIelyFdRJy3By14P8z18UX3XWQ+umSKakKTTy3dIFxCT5Q -JHUbPxt/39JNnjoYXdgbvpw6otYDSe4WreIdlJyZkk2iowA5hfCbmK6RVfNUhVIm -ZuSTCgMpyQBEOEwoGDpFvAd1Ol5RL/ubSGRwjhCFrbhnk56UCzxx3MYtzJ1e46a0 -0uQwi1E10hlaJXBfj3o0CU4d9nwc1i36y9yivtb8lcO1ukBZOEjX6jxlS9g3Sot+ -RAVYhOEuNh5G3RoQMI59yqBAZhhnbcZ8Yagj244DxQKBgQD2t6Q8EOGx6+X7GeVc -NVg9k8dk7CztFkHxz6MZPsjX3d9p3DJo0iGEjHCgVo8lenVqo1eiKmqCfTYddDn0 -sUBlZ3Rxctq1mU/sXTyMmfu7D22GQFBmXSQ3xJy+Z2t6pLq6lIdHA13nJYulvrya -OeLFogbJG4JtkeqkEtXiIEsYtQKBgQDp+PA0QpRq2wTaBvXthi74jd6u5gvoHOYi -9LfOvJASQHBr4BgRI99+nIpxYS3I4CRtlMbJK/DfTHfjGPCxLAsowuychwZ9FRvx -ezT1Yb1HDFcwvX5a2IfpljxQ2C2Ai5Khjy2P6WStkSDHz1KN4GXenaPuuFh0Mvrh -41Q7frVWGwKBgQDiW9Eqbw6z8EycWsEOHb9tF8YMuYfqqs4sLyZkRi99pwqRFL+H -Xqvz8epvoZtKdpV+FomTtrjsKjdZRMbb0zjTEN1MLWWu0g/7O/wOwESu9tO1JhLe -KDzPkeuB4l9BMhxEjXukUtl39wGuO1bNZajDTQpOv5emMgeHK+TiyGA+NQKBgGKF -HEAlOPG1v9k+zRdzRRwMQRRMcf8PDCjz+uHmrJPC5pPGDNxKyrU5nWIYlXrcRvqN -hxb2lbqxLFpICjHQZfKIAbH3eVf6J4YLZ0VcHqNoIt63LBl8y94kEMnJ/X7/RoMZ -EwpiMK6VScRZHF35e2u93WWL4lMrlFDBtJpIxHq5AoGBAMo+RsIawRdhsbvZnXxp -VY5CchPAtxwfAV1jnhboYjpcRXit8XP0Y0dPp0BORI76IdJk5Dfea97+u3Rrv/8r -nhk9QySjVz6PgNnPj/mEmUy9EZ2CZe5JpY32tm1BKjBHIINYDrC3lYeOEWs+Owsl -+APzz9O2G6NPkm2Zq3WoaEJ2 +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3siaf8bm6GP56 +O6+bgAtZV+yzDEOpLHhk+/hCc0Ao/0NfzsN24NY8tDOhsSTrOyDd1PaFAORGDLD6 +zysefKQhGq+h8Yu0ZgAIFLZEwe9TEIKpJgAyWvFO3kT+9D3fVrFzint2a3EqixGI +uJ9qKxEZIUeusImL/2xyOgcxTtc6WO38bzMFW7hv/+lcMantI+5I6ZLVBmCDvjqw +HHCqsWQOZOeNOxmOqqjpXuHosyPPEpsZ+Mi5Y2x6sGO7bcnQ7SDQF3oOOe8C+FaN +91byVl9u7igXhu33ng+cVs3VEPJX3vCeYBKoYxWfBqxTUILbO0OjGvFhUABD56Tl +hqwdojexAgMBAAECggEAA3dAhE8GvoyfLIY4w3nQfQCMLjqigiwdH2ajoflTshJS +3pljlbgbQqzxtnDFrgyBC75rYkoIhIvTwP+spBgc7qT2wFry1FYCVSSy5aw1DD+o +/3EAmvKdT+wgqCDKlA6qLXBk8PCJA5D5JTe6hkHGwk8e75xUFAifLq6KmTMQG4Eu +xZS5OpZ0yjb8p8iB7bHY05GAW4d5otha6nJzOlC96JlqTOhav7ykmtgHN/29Na/5 +buBfogpsT7ctDh3leejGo9ubN9mVkK8i5pjZjPq1Zdh7mSb0J8wt2FlG4WiW/WcY +MDKxfxTHXLDNLrdk2NgHBWseistf3JfKnynlwJIyiwKBgQD42oEDBjjzRUnZnhUx +QfOSSfhEt6ABL9qqIYwGtLeZMHNaLXEiNgV3cNDmmr032Gr7mfKmMrGlckdlvyGx +ZciuFxmFrYybdcriQAkEuRV0ZV+CSR49czwp9csjSQZSRZ4LdT1+Y5MVLBr7K7P2 +WNVmGJJbix1wxVkAmKcEkX6AywKBgQC8+KCxH2UmirfzoiCr+MU2vzYOcee8UvWF +1Pvu0q6yDjgsGptZxeEPNY0Je4Rsps3mVlijAn2IELG1kNsI09myq0bQxslltw+F +ISjHO/6xKNgoNgUKoRdVprozq4RiK0mSY6WyO3Bc5ZWx4CsUe5d6fFKOm7ojA6ZN +j74HTt4F8wKBgGpkaLHVUDXZkrhCWMclbjBGBanDY9n+DpucGhSn4LLSvw53zR2W +QQIOrpFY6LregOauq8oYdFDKqfG7JHmGjaS4ZYX8a9fvJV1TiUeGpcCMsqeuAQq+ +oKND3aRpTRWRg/9cEX1ervxnTeXCin8w/ZNXwAL5WA3loaaanRVb6ty/AoGAT1E8 +gZvf5RGMrKJ8fDJq9NPFaMK+tflMPORs6o1b7jixszFny4KXOL8Nd9F0f/Zzrh7I +DYPaFOaM8NzgUxA47BmgG7mUhzETPpnwd8/i05GFSTuDWjbLiJP2zAFOC7aHpv5U +aj8wpo1nC8Y/ztUhe7P7IwiSVGgPwbZ32LFt16kCgYEA7NCI/Ca2n/8z9yjRE/CS ++sb94yS4yTqmuAaLiWVnesWM9faC39MsEwtWwJNpZj4uMEwOjfOiUjCMa5/+sY0w +EuWRykwkqM77S0fjT0KKcXWNCmorOjfNwzQYF/AeRbP13G/2Kxbf/+Rj1WJdURAR +gHqYIvKQbRIOQDxZEjZIkXo= -----END PRIVATE KEY----- diff --git a/src/certificates/discount.pfx b/src/certificates/discount.pfx index 853c7ee..251a259 100644 Binary files a/src/certificates/discount.pfx and b/src/certificates/discount.pfx differ diff --git a/src/certificates/eshop-local.crt b/src/certificates/eshop-local.crt new file mode 100644 index 0000000..1c4c59e --- /dev/null +++ b/src/certificates/eshop-local.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEdzCCAl+gAwIBAgIUAfT1chDFp31Leol2oRLutw0pchMwDQYJKoZIhvcNAQEL +BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQzWhcNMjcw +NjIzMTEzOTQzWjAWMRQwEgYDVQQDDAtlc2hvcC1sb2NhbDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALghNfMNWZ+3Yor+Bpc6l6ER2C6zHeLN9YhI+5lB +rds7SohpAG0izehL4f+pf1YnBpybBF9ayHehWpiv4a5aDmQpWMIZGOmL4SCFzLwr +RWE7Mi6mdaBCPxWVd7tlhCMrw46JHlqfY+QFrizZo5rJK8oDJe16lNtNHWuJ0700 +C6TiGJVuRLg4i2ZiOeYXApNON02iqd1PPwwG/Q8tngZBtVLYqymRT3TovLQwqRc/ +1cHChcFV10UuCuWU5iKtpPFx9zLFVSaWwOLPmFp02KcgRW3s2h0pR3YwFFuuxivX +TgqBfjduK4/tVvWviwxKfZH7jIwpjqRUdMue4yuWwbS3+KsCAwEAAaOBjDCBiTAl +BgNVHREEHjAcgg0qLmVzaG9wLmxvY2Fsggtlc2hvcC5sb2NhbDALBgNVHQ8EBAMC +BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFARefAb0IBMM7Fa1Wayt +hx+DsVfzMB8GA1UdIwQYMBaAFL8SW3J7YyDeS5LIlfi/4Iq9KCwIMA0GCSqGSIb3 +DQEBCwUAA4ICAQAhIuq+KD5tGzHWd0Vpvftq+Dxe2i9QLcwW2wjsY693Ws/EqIjV +dOfrYSDju+48JVNpysx/fqQtEIjGdMPyPNe6dG/gzYIlvHb52UrBzyha08DbsD+v +pa5t70UZBupCJgaFebrB2tz/prP7QuFGbsN+pMon6eBCWszReqQC4kPWt695NDT2 +NYAc+NIyYYn4IJaOfu3n6wEFkPmF5KnzrfZ6OnH3peRL1USM9KNg1lLDUlmrmYKs +lkl44mlaueTRUJxde86qS80gF2O2IKKJnKwddZ3dSzwtnnstamzHDyGVpRWWMXqQ +wSo3+cscgl1Y7HC9aHEboCS4d0iJAG9S1DrbeojwWz/4sEiFwboEb1TaIy9KijRZ +VbRyvWulBdysuXsMJ9tsorj/VTZG0j+Bhzm4kXx6Gb3P2ifQ+en/JmxoxT/XJE9a +MT1t9J0VBiKmiVPjxyJ1vdDAEAbPOAYA/GAFBxfsJaHFAI2xptamPCqzwj1je07/ +0A26pwZvefEcRJ8Z8md/HHV+0fyojINcYASOHnl5tooljedzjSTvau93RbJQBdD+ +/Y/eGjZbKsCV+eE5A8R1kFgIda0EZ8z3J2Ae38RiHfzFK0q9w8DmqUYFPl5FOq+/ +xtK3BicI9dRMTlKZJZ0OjNTYrrULR0Dh4cj1vhg7I0E1x6nAVdp95FvgZQ== +-----END CERTIFICATE----- diff --git a/src/certificates/eshop-local.key b/src/certificates/eshop-local.key new file mode 100644 index 0000000..86f24f8 --- /dev/null +++ b/src/certificates/eshop-local.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ITXzDVmft2KK +/gaXOpehEdgusx3izfWISPuZQa3bO0qIaQBtIs3oS+H/qX9WJwacmwRfWsh3oVqY +r+GuWg5kKVjCGRjpi+Eghcy8K0VhOzIupnWgQj8VlXe7ZYQjK8OOiR5an2PkBa4s +2aOaySvKAyXtepTbTR1ridO9NAuk4hiVbkS4OItmYjnmFwKTTjdNoqndTz8MBv0P +LZ4GQbVS2KspkU906Ly0MKkXP9XBwoXBVddFLgrllOYiraTxcfcyxVUmlsDiz5ha +dNinIEVt7NodKUd2MBRbrsYr104KgX43biuP7Vb1r4sMSn2R+4yMKY6kVHTLnuMr +lsG0t/irAgMBAAECggEAHF6Vkty4NdkJ+FNaTZur+BepQMy9KpBEJ9ri1QKfGFui +yLCw7Z/CrOtgJ0WExo/dv2xM+Koin/f+3u6ebYAXnowWTlWSlo1EQwAKguWB25DE +0xY3olkCoj80wu1JtieMil4LDLhpKh1L8EIaKIOdWRMyGUxdOgrAIS0LsCegMaeW +rUGgg74yKt3qFJjTrJy1LbVUju09IqFQvG+wwrY3gmLKSSLHoZEbuYiD+YCjR4uM +IZzRATTZiEMHhsBRsbN+8crloCSyBJd2OCb5RNaCwTf3VNWxRdu9eo4JF7C0BTta +ijzfk3hPHzPLSXNBmUxoO6a/aSGoELCKqTJfCIlf1QKBgQD8NS480We7mStYw4XM +TMtS6T4iqiABvZ/gn63QtRgoXbGLl2EWZjCTJ1u6lu3YRMXNgHad8kWgKNAKDcNL +H6R85amvmDi02eUQv++msXbDvujeYwFu3UHz8kMRBjHL5zbe/CP47hxAytOQqgav +eqj9pqv0AblMzBYVCfVXApQnLwKBgQC65fp+cSXfZ5kl9Hcq9PrKeJYCkqfamTHf +ohR3RacXlY1uJCsOi3L60kEcpJWpkNfDd8zXFMWWu/6BMotKuK+VRO+MLUvGtoUf +jYJoiUwRAowm6HZCdO3J2Y5MOz1XSxLADGoo405Tv8VqEcgBixISkJWmTO/uWYv9 +ovEVB/LnRQKBgQD2K3JWKo71rSuCGFYgc1SCOOdNLoDPMic7OKCPdjN+MvV5Kui4 +1EXVXDVMisTcs0PeseUVhcQv76YgKg7U5K3IuuJFYm73FzdegfmI2u7xYQYrCrf7 +XjthwLV1iHZSb/w+6hyyfLdXBqI6MbsUzMTl0ClGoegb7ZggMPgnVX0GQQKBgQCQ +sFosaQwY1+sIJynaZ61/8bqwYzjvUon5x1BwxcuFxpGnIvjyWaK56uvdcM0saKWg +/a3nFH2jJAbznl2Xi0LjHGsW6jovrD2DH9pFc4Uf5gj6Vhy3di5ghbxT58ilO8lY +REQrQ03wKBZ89ycPisqC9Mvl4soci9aElRBuZ6j0wQKBgQDQrE9w4bA3dE1+zhBJ +pkNjlbEz+OnIDoh7YIAeP2KJXnoaqlNGFEZfmKXU9OSxvBbg1Zta7pY+oXRw2+tR +kg9Ce1r/X5pN8VInZApDDcClVnZuPAieL2mb7+wvWznztIoMLnnQc1k6UM6BSvp4 +96dc4hr4jGECBO3e49Q/C9KJEg== +-----END PRIVATE KEY----- diff --git a/src/certificates/eshop-local.pfx b/src/certificates/eshop-local.pfx new file mode 100644 index 0000000..c8b635b Binary files /dev/null and b/src/certificates/eshop-local.pfx differ diff --git a/src/certificates/generate-certs.sh b/src/certificates/generate-certs.sh index 26ff6cb..929573a 100755 --- a/src/certificates/generate-certs.sh +++ b/src/certificates/generate-certs.sh @@ -2,7 +2,7 @@ set -e CERT_DIR="$(cd "$(dirname "$0")" && pwd)" -K8S_CERT_DIR="$(cd "$CERT_DIR/../k8s/00-core/certs" 2>/dev/null && pwd)" +K8S_CERT_DIR="$(cd "$CERT_DIR/../../k8s/base/00-core/certs" 2>/dev/null && pwd || true)" CA_PASSWORD="dev" CERT_PASSWORD="dev" DAYS_VALID=365 @@ -77,9 +77,11 @@ EOF # Clean up intermediate files rm -f "$CERT_DIR/${SERVICE_NAME}.csr" "$CERT_DIR/${SERVICE_NAME}.cnf" - # Copy PFX to k8s certs directory + # Copy PFX, CRT, and KEY to k8s certs directory if [ -d "$K8S_CERT_DIR" ]; then cp "$CERT_DIR/${SERVICE_NAME}.pfx" "$K8S_CERT_DIR/${SERVICE_NAME}.pfx" + cp "$CERT_DIR/${SERVICE_NAME}.crt" "$K8S_CERT_DIR/${SERVICE_NAME}.crt" + cp "$CERT_DIR/${SERVICE_NAME}.key" "$K8S_CERT_DIR/${SERVICE_NAME}.key" echo " -> copied to k8s certs" fi @@ -97,6 +99,7 @@ generate_service_cert "order-command-api" "DNS:order.command.api,DNS:o generate_service_cert "order-query-event-api" "DNS:order.query.api,DNS:order-query-api,DNS:order-query-api.${NS},DNS:order-query-api.${NS}.svc.cluster.local,DNS:localhost" generate_service_cert "order-query-event-processor" "DNS:order.query.eventprocessor,DNS:order-query-eventprocessor,DNS:order-query-eventprocessor.${NS},DNS:order-query-eventprocessor.${NS}.svc.cluster.local,DNS:localhost" generate_service_cert "api-gateway" "DNS:api.gateway,DNS:api-gateway,DNS:api-gateway.${NS},DNS:api-gateway.${NS}.svc.cluster.local,DNS:localhost" +generate_service_cert "eshop-local" "DNS:*.eshop.local,DNS:eshop.local" # Copy CA cert to k8s certs directory if [ -d "$K8S_CERT_DIR" ]; then diff --git a/src/certificates/identity.crt b/src/certificates/identity.crt index 3aa2d49..d2e1655 100644 --- a/src/certificates/identity.crt +++ b/src/certificates/identity.crt @@ -1,28 +1,28 @@ -----BEGIN CERTIFICATE----- -MIIE1jCCAr6gAwIBAgIUAfT1chDFp31Leol2oRLutw0pce0wDQYJKoZIhvcNAQEL +MIIE1jCCAr6gAwIBAgIUAfT1chDFp31Leol2oRLutw0pcg4wDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM3WhcNMjcw -MzE2MTA0MjM3WjATMREwDwYDVQQDDAhpZGVudGl0eTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAKdwaB7tGgWjUjuCJS+tu0QSKy187jVmMc6n2Zzm22uy -b4V2f1ZcAD/ZyOCBNikPcpHKNRiKobeMp8xPXB/UfyenhjS58Riu8z1TCtBPb3OA -MmCNNyNN7qlz3eQrMzbCjWoJjZ973qMjTzP4THWUbnS6yQXk40entuZgeYr0szdJ -+aZQ2rLQ+IEeqf8eF7cnstu4FjDTwLY2fUAszgdjqWHirNeu/MJP/79WZxnBDgKs -DyAakPSQyshg54Oc0Ai7ywMpe6B04VWtPeD2IGox116NH+GuuMN7R9OH0CToX2TA -z6yGF+bvX1gLC2Gm1OYEUIg/AACYSaDXELGGQ4X0U4ECAwEAAaOB7jCB6zCBhgYD +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQyWhcNMjcw +NjIzMTEzOTQyWjATMREwDwYDVQQDDAhpZGVudGl0eTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALPOe/+aKn193ifxPb11odvZ8bxPNu3Z6YyT/F8Ase4a +VkN0FfeLYag2P9muu9K32ARs8Yb+Br3ppUaryLhUGrAKiPFaa8d+t9nQFAsVZHD2 +D5qc9EzjNtsEc8xxp0YXEPRfe2cyyeuHWA7Y9424VbUGnysFag8u6cjXk/g3GY+R +kwqUymAAPEstldfc0pyRQ66VNDE+ACKgW5CpphaLQmRUDGvhCKo8qxgTVMM5BOJi +wUxE9bpzSJJfP6+Z8nQl17Xdd9tg8grUyY8TLMhZZinYFL9Rr9ThLBAKnNhiPdCz +CW6Fd4XSAzJvSkaaXG8oVmoxqn1LQMW5PqEorFnp0f0CAwEAAaOB7jCB6zCBhgYD VR0RBH8wfYIMaWRlbnRpdHkuYXBpggxpZGVudGl0eS1hcGmCIGlkZW50aXR5LWFw aS5lc2hvcC1taWNyb3NlcnZpY2VzgjJpZGVudGl0eS1hcGkuZXNob3AtbWljcm9z ZXJ2aWNlcy5zdmMuY2x1c3Rlci5sb2NhbIIJbG9jYWxob3N0MAsGA1UdDwQEAwIF -oDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUHJr5E7LeI46GFhlP+4YJ -EAJixGowHwYDVR0jBBgwFoAU8eeswamMHHVWaxqeTxbj4FYlxgEwDQYJKoZIhvcN -AQELBQADggIBAIFi9xJaGSWmYv7BFb0QQxr3ZNCHVquPD+s7UYdyxmG64fkcvA0C -/6UjqmO24IHibLD8ScIRbW2mg6g6QIS8AJx/Eix0sqfFKi7SwhNVKk7UrlYmILcr -thGe2PiQjXq32p/4C4mdSuzUL2aLO0OjUrVqH+scwVK5HU4NQpTdhF96RZaHQ4+k -NJ4G8OXUvuoOuZFRN8U6ihV4vUrV3A+t8qoDOJoxcUvfjohwZoUNsczyTXCe06ER -Mujn35XbX1ruDH+l04RuhbDFpjkJtaLGIqFvrGNErNxXKltZC+uBQ345NjmEBb9H -D52MF6ODhm4bdxc65OVzr7axI6yBWjhNTwy0lsu4lAUuX5cH4qpaCEkpe9wnTzuP -7p9nnMxS0q87D2ssf7JDUKjbHKOvjHKbWlqi+gQJb9VPnHTsXWTt/jWQCASO84KZ -IFrNBFdh0m2MTUHfNClCFnEBzylGT8PmtnOQxFNoX4h2fMpqmvahQCuhQy98/3hf -FB6eqTGjBzdUTdRgWYpKeO9/BGBIkRy97AGwSq54/kNIspgF4DSHtq/N/2lwbpF2 -OKhjgwQIWGCE8WzErBOsTK+ULPh4IwOtCjZB6h4hEjd7Es1rhbdzw3muzGoQf8db -f66FEqMIMaYctsnRvkpMcGEWTgzPp0lnKiX9wLVKnTgDPkLof0d5k7Zp +oDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUM3ZPspqN320a7PYFjuej +o4ksmvowHwYDVR0jBBgwFoAUvxJbcntjIN5LksiV+L/gir0oLAgwDQYJKoZIhvcN +AQELBQADggIBAIl5IQ4WuhmOaT4NE427n1b1GnjO3nYSQ1ZNuCFFlpm192xrx6pw +2h9R7LkssPR3cytSkRFn98zsNIW7tFT+EqoaUifRgQetHwJpddAylbFGFaxaRLRK +cgfwPU1I/H9pyag9o8z17x+uJuIpcy90l6nEeLda1e5Jqlh6MJcyzRx7GS+ioInh +rAv4ntIT8RqLvXaGAwIJyrrBepqLuiFUjxFSPmrb3oBOCxMyENue/0hNQheG3ZvF +6Tu9jGT11sUSt/rnLl9HUHZvaGbCIIhuvCbrtUPzN+WFfQvTEgbz6bxIwRWw3Edd +A2dshHndxWkIo5Ys1Te9E5VYXm3uBcB7K6OqZMEdIPN0Vfh7VBD2iMvgmtQrlVS8 +/tm57Zj51y+qEYlMjfdW8psNDWkiXqIReLcIWGwiYSkq9kjNHz7SqwDrg8/vX24i +cfRXXqETWdDcEtg7bB6nbN0Ual9p9+JUug/q5fGzEEXBQKaU6xuZypAglVig0wAr +3+Sp6TfQmcClvny91pnFzeaz11Ok58LDR9aJpoDJ0i6dsRvlFX56+y8EnWVIP2HD +Tt0KlmgeGD5jwbM0nPppZe5rAbfcekwqpTLW+7lsL8hrrgvKO2K7lqqFnBQNpXWf +4RVAY8R+hHizObBpAWI6XEG0g5DQNbQRC4h2TDoZiHU3hwqH1e0niaFN -----END CERTIFICATE----- diff --git a/src/certificates/identity.key b/src/certificates/identity.key index a01e951..d4cbf30 100644 --- a/src/certificates/identity.key +++ b/src/certificates/identity.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCncGge7RoFo1I7 -giUvrbtEEistfO41ZjHOp9mc5ttrsm+Fdn9WXAA/2cjggTYpD3KRyjUYiqG3jKfM -T1wf1H8np4Y0ufEYrvM9UwrQT29zgDJgjTcjTe6pc93kKzM2wo1qCY2fe96jI08z -+Ex1lG50uskF5ONHp7bmYHmK9LM3SfmmUNqy0PiBHqn/Hhe3J7LbuBYw08C2Nn1A -LM4HY6lh4qzXrvzCT/+/VmcZwQ4CrA8gGpD0kMrIYOeDnNAIu8sDKXugdOFVrT3g -9iBqMddejR/hrrjDe0fTh9Ak6F9kwM+shhfm719YCwthptTmBFCIPwAAmEmg1xCx -hkOF9FOBAgMBAAECggEADCkHHNDgMg7glOMQr4/k4O6XXW48cBsgDKfGz4T6JE4R -GJ6opJVZrMl0s+5aaDy/l7w5YzMFR+rykE1mrcadZfw+DFQBQSdKkdZ3O3X7bIZf -0kCLQ7iAF+Uq9SxYg7Z5Nf1j4FRrEMrKkKYMqoDpTTe4DAIpqf1xlHVm+lsnbWFH -SMDTfxbD1NvhUc1m8dUrVuLdy0G4oltWylmdzy0Vc/wixc41vAU7wx9X48fJVcWc -fdrAIHO+eGLepNdzSprCSYU40IO48KkDESRUUfP46Pj7OlRxmO14v7m7dzKqJ43/ -RJGdjGDCHt9gLrlNV5ml6bfuE5TdMZgqaeRDDuxEWQKBgQDTP9I/awLPheVApppI -jb/uymiWZ4RVXk505d+cs45Bzp89CyVhXok0OSV8f/9+IzWbiQP19iIvIgBl3ozE -mzPJb9hzi7Lo4NsxFzvjgrKe8m7/TPZepwbCU5Yqbv4Kwc2Uy13Kc4NgfNLteenS -fIn173ErYhIfysDEnVEqj73meQKBgQDK6LsWsksz6dHl4HksWmQsVAwu7tvMnFft -C9pyFwchGUk34N6WGYHCXkGW3qVrS6KtFshm56kmuCsiyfmMXpim5dfy1Ghkjv1n -Cfd5m0KVlsTWv/624pI997LsP2XudWz/PbO8XTm4KU9BUxNI8Z+nUp2HTTW+4rNg -xtIImB+zSQKBgGQC3BQAIqWC+4U/Gt3slgiENT23pnQQIM7BIbt7WocXPlZVF45g -hk5+G5w0sQ3Tt4Z6OLDSpV5xF4Ui9rwBymO8mtohMkOEaOF14XmVn+EWX6xokF9B -bjbEAdz3DTikhiLCoRW+2Fzu26FoTWXEZkBT6t0iIfiBMgAjhpDC2qHpAoGBAKKl -vVorHvcFBXiD3/26kzOpR37TfqLb6+sapkbvyIoyj6tX+HRPC+F21pKN9AE2xraC -Xa+HIOLlm8YuKnfnV+vor5p5wxhgOiW/Kn1zBAOOsEgH7LBCm8FKbUTMaPOlcvKC -TjG+dMb3bg1J/1poPHbOVXGgZWWWqPz5QmEbN8XpAoGBAMANfHjgR2X7Ig8KsDUT -qs9a5qFjF0K4GhzMQ3ciegaf9Xcf00aTDL8zq++rYWIc9ZDKa/+t+YJUWM6n40gH -x8hNuQfMSBUvsVElCNkzlms8yN5bRPQhmFTMDACd40URMyt6knR9gcACMOz+Kaqd -xtzz4zLjYDw/usscQnPo4q2b +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzznv/mip9fd4n +8T29daHb2fG8Tzbt2emMk/xfALHuGlZDdBX3i2GoNj/ZrrvSt9gEbPGG/ga96aVG +q8i4VBqwCojxWmvHfrfZ0BQLFWRw9g+anPRM4zbbBHPMcadGFxD0X3tnMsnrh1gO +2PeNuFW1Bp8rBWoPLunI15P4NxmPkZMKlMpgADxLLZXX3NKckUOulTQxPgAioFuQ +qaYWi0JkVAxr4QiqPKsYE1TDOQTiYsFMRPW6c0iSXz+vmfJ0Jde13XfbYPIK1MmP +EyzIWWYp2BS/Ua/U4SwQCpzYYj3QswluhXeF0gMyb0pGmlxvKFZqMap9S0DFuT6h +KKxZ6dH9AgMBAAECggEACkMISacZsk4BZIP8pl6OmjA+/ySbbNZPrkTxFaNbarLl +f6kIhFDxbGFYO75T6UVLybwSY5MFsHrWtdW7bJjqnJrYhCnJPLpkyyre3sXd4Yjx +jNa7WW4FGFl4AGmJU4Ztr2MjQfMHAIjmnV/qbpPgJ41useZeGx3uAspNUoO87J5/ +BC8+BqHa1MoRDORq430Fh4iykkUUdhSHSCSHicbQOOmG/8N7VAAbzPzJOn39rKn6 +sysziBDQHZfNx8tel8D/KG/Hyhp8DwLWZQcjF7oufQ8UGsAaC3cAq089yzvVNVfp +1sUQRnyz3aCMdYBIJ7Yn4xVHCzP75M6DbyPc5cuawwKBgQDqcZjicZCsJlmu4ZIC +Hm5HkK+zb8HycHz6K1ig9VCeB9FlmlWOUPk5KHGjBMSqtQsltLIsccGnzGnq9dBu +Ai2utnNrcS2S2N6cHbuK+uWZdqfKoybgpU5o6igp1GXP7z6WT9qViKpkjgzOXfLD +RLYXAGQDmnRdXZlOaodlQ1ZZ/wKBgQDEVtKCsPKBViJ+TsBHYQigPbGPhzcGoNtc +F+YnQWMiJv2mqyf0Wc75bXBb50JiP+2Hg6Y7KbFSQRZUWXMBYXfjlG8hz7taACYI +cAapZvksvoZxLPvBLX1GhlyyRB9xMCnlKW78Dj1lFfWOiulQaRzSvhgcJusgmJbZ +gcgI5zE8AwKBgCrqop8JRP+OgapW1qCWq39kSBWj5rAX0XkGSFImthxHuBhOWU0V +G5pQAgVikRHi1GiRnHAwXs/1xonhd8c7lNs/wP8xF7OjCZUwiC1X4oHmS673kN1c +xW7FNpb5r62R0TY45f2rp+2CZ2u7nP4L7P1m7+gM9TJGORM2wxRRcFRHAoGBALti +cb8xygEOiBUsa+6z+VuWBeUKE8ZLt5AJbyuACHEL7YIoUBWxsQv1Gwtbh8vlX3m6 +d+h3PjlWzUzrogtrTtTxUa9fZ1vaUHI1GOaM1LuTixRw7kXMeIfarJWm1qtcYF/K +T5ZYsNfNQXMtuMd5ynyH2NLlgfq2JyKn7pYwsJipAoGAdi4n98uYkeeNJWQl94Yj +au2K0tPcaNGWQY4mBGIa9sCSLo3ne/oaNN5UZyrb5q8nqA/mzHoGehob7slgoJPG +5EmRayk6qY3YL7acxM5aeZkHax1NNTFvQ+pbuIMeQuvCyANyfXCZfvY4nVZZ5Juc +lpo2id20C30XAt6jBfNGVoE= -----END PRIVATE KEY----- diff --git a/src/certificates/identity.pfx b/src/certificates/identity.pfx index 5a12691..c0eaf0d 100644 Binary files a/src/certificates/identity.pfx and b/src/certificates/identity.pfx differ diff --git a/src/certificates/order-command-api.crt b/src/certificates/order-command-api.crt index eaeb2c6..2fa04db 100644 --- a/src/certificates/order-command-api.crt +++ b/src/certificates/order-command-api.crt @@ -1,29 +1,29 @@ -----BEGIN CERTIFICATE----- -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 -XdgCo6p395bpoMh44Wzv5lMIUmx5lTBuP6Z5 +BgEFBQcDATAdBgNVHQ4EFgQULV0p1enE5a6L7//j/m2VO1MtGGkwHwYDVR0jBBgw +FoAUvxJbcntjIN5LksiV+L/gir0oLAgwDQYJKoZIhvcNAQELBQADggIBABEl5UaG +vugX6BrQES/wmCtPXV3MkzsqO5BNhVUMjhKVd0L4z8wtegBPj9TwocIHs8ORX12U +iiuwhYjOicOMFshYPrwgNEwKJLY5L8cWpVOCeVSTzaceXGk2L38H+Hg6G2ndmCTt +aoBKaa0+s6yKsrlXhK9OXointgpIV6qcqdxws5SalEn4cnVSoFLiOQrLiwpplwH8 +Z9GS7WvCH6i6UZh3uX3xkdyDAyoUgX44lT8Drzsqz3hsKfl6JjH/aLLBlk2WJfwl +riHkRXh2qE5ROH7Ho9u1tm/ZcgnnqEHsC9qqJXiRsXd3Z2ctrRf/bBhByoTuUYqD +mJHJSk1sPS8nnsbwBzULXeDzpG2I+NPgDx+SK4fr0gvacHX/FXqu82iajtdErj7x +AFwpR9kZ3TIBexT22XDxKxQmlT8MHruO3FfsbL/XIYBCH1XCZOoKlTJn1d/U0j27 +OQMPAbp/mHEeJqCqHpykLzuvEEruuSgKpgnUD88XM92H08/79vECsyM1wmXxGg0y +QEQUlyvpRavKQJquXpt+RaxUxIIvpdm2K6ddDM/T6wh8NS5QMMBOdL18lIvSDDb/ +Di8RUtb9B1K080aW7S3I1ToIPbphrcQb4PZ3x3Cv8+UymFUzhhy59HkF9Txu9PaX +8JhSG+qYFhRdjpCELaZAAicYIxC9PtbY7lAK -----END CERTIFICATE----- diff --git a/src/certificates/order-command-api.key b/src/certificates/order-command-api.key index 2430d19..fc78cab 100644 --- a/src/certificates/order-command-api.key +++ b/src/certificates/order-command-api.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQC50b3x7jFjVuwY -4C9C0wq5c9UpL4Gm81SwaWuiHb0TyG/GJ2an/Ku85if3jCV1MmNK+kHA64NkAb9+ -01tDcmeEH8YJSKUHlSY+h7UtjkMoS0eXdwnFthDFlZ60JkoqCrET/IifRlApk20P -3tJHYp7iYbRRlx0PTKiJAuF09OFo8zaNhLn7z7l9aL7gZaYME/oYen1AuatnnXNB -7LFcUx9sBGaxkKGv1orC4NrYus6iY3Hj6VHHoW0f9hxADp7hOlWwNSS/OaZT4xm3 -IsjeI76uHz+phlddtUQM1ZaJaDE+3gf49LBM412OoOJnSFNIr+0tNAARkqAtCStH -Z6dF2LtZAgMBAAECgf8KMuS40zeiuv3d8p92B+2GdsWvTGsGpeT3xQpfwD+7uJse -EipdSUSHXTu6RAZTxga9uSIsPzK1xuxED61lny7nBIbWgrf94MX1CdV8CD68tj8c -bF8i3UJvlc8CfuzX5EC1CxWCzl8VnT5NZp4J684DL3O5v5UXjIvLO7Yhy7wKAJY9 -Wq8YHzfs5xDYbjBOp+gOn3B/nVgtNpeoIDUG5M2lRbNx64sWNEF1PrTZD5nJFGyg -KU8Hgbdu8ND3iaus3KUdOUG4eEXRUg/dl6FIfhR0AufH1Hs8T4eXYi7d+ojN85lv -ySio5gblbWSq8B4LKxr94GfyuAev/t9pRTSjD+ECgYEA2qEozfzXpHDOIfM/84kN -xVSyhfcjZyk2Cp51GsVNO/GK8HQTjNVcFkqjzU95ahYEQpn6u9SkIS51KWeVdbaj -WUvlJ0iYMDa5u7POSpKbbp3HyqJdNPVyKqZwBxDly89Ot45QHgT+PyOFlkqucuwx -cIZuK+1P9vymB7ayX+GAjSECgYEA2ZTdhjKVmeFR+tfKkZZNzgbPtEwPYsk0MxVp -Xf4H4pe3Yu4ahYEH08hxY+e/VaIigtkHpyP8RopZDthu5QLcDchMRP7GsmppucR2 -Zb2eNTftDghaxEJh3K6/XoliiRod7dMNHJf+ZWJomhcSszuJhR82sff6hMT3LALX -a6oIbzkCgYA7V/VYfGIYO5poMrvQIgp/3q6amGueq9wEY+CLhLSjKbw56ngICT32 -uwndR85AEnvTjDI32881RoP82iYCjrGmImiwEg9lPuWJYpQDP+o6y08Y3JuKLXlw -xD6yXE7T1JCcWF+81kQg5UZ0dg8GGMCOt56eA8tp0khK3bdrOS2IoQKBgGVumLbu -7f8Go4klADJOt4bMdhe/PYz373XBDZXbzyE7SSq9hW+nb1azoujIKNJq+1u0gXTR -udHIvSvGiiwI4T0rmyKvA0I5iYAormlPtGlq4QAhtO65Y5XVgTE5Ks5vdnRgZ0Rl -NxtcfRcYmocjwkBlBMKCsC8lA3Vo/bQbWENBAoGAG4E6hNK5lhVhE9B794Hk7qhe -3kbTJKJCUrudArJohd3jKyjS7Ba9Gi6uOMBLN26uSUdOJmaM1kiGU8vWGWZxRti/ -Z92NHdzKvicI0Bf5s6uPK83TYXK2qJra9jM5Ch8cW5tD3duvdqMJH/DNLrsbkKXe -8t+58l9SbfrvA/XrnLI= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBUMK8OCbGJYlY +6vvQ7+KLNtGj8RX4A1n0Nyw6E/nNYOC1B1nU6+2vlZsyRSPis8JJbIZDp61QZHK0 +bls31wmxelbETS5ckq4iAiil+pLXpLIVXeYYhUhB92i0y+r8fE1jjAGqCVtCiQiB +GwX1brshX9zLYBWlMbhQoYLXJMCrxKk0CZnfhnMj2UiTZqbgKroGn2log4qo4ckK +1fAKSVWpjg1hmr4JN4UeogOSAhO/oUfXqBwrP+1kT9cldSYo3K9eYZzKJHilxRGz +4fKB0M7HBezIBRI9igGIPnhNM1VtZ6r0uXEVNSjb9F0O++Wi+2wVbUJgA4ZTER0/ +hAzu5sL7AgMBAAECggEATrUOBEosZ0KDMEPEMSZqK1ovcrtGwYrDxi3sgNz/OQJ3 +mt0aUxmX1YRpAsepu7SKpxBbfhI3+2JaXWING6ge1zbDOvtdo+1InqoYWLOzs77n +jtGDTHp/l/QemnXn/9KwQ5aOWueiU22tm7sf6vShlg4MvHUreu3KaHHJ7sSU+ZnK +kA/fgmLdJZtuN41QyHEq0C2rL65pKRIDvg9x/6tjpXRctrVfdQPI/9L2AiZpNk5l +P706EY+OIwfv5HV+IABmQVeYy0w0gb2tzYyagf73HlHmLd6bOGlupLMFNNMcIRfk +rB89S2Gp1IR09Rup2G57EStk5BGrD9LSrNDHRfkn8QKBgQD/mmn9kioZFE4jcsRe +V6ZgYpJjTOygzLwNPnkOEpBeKUbixT25pE/8/tUw/1GD8dtvkoYSIA+MLZdVnP0i +yGRsb/2fa+MZWcrJT9mn3W8R/tHFLhVfxRDlAmiDDKRIYvSUjmz46Y1aFNmBvdzO +3hKNM6wh0FPbLwD/abzAVLgcwwKBgQDBnZddHODIshTmLju4DE/btvJZRCq7UHIY +UsPdjaL25e16nZJFxj57rzQugLm4fFAZs1/dmJ6cCg8zAFpwQXw9lIYa6NU4Nfn/ +1AVMM0DAcbtSTpYMfflOvLemrYQnB4N3h8YA95ki40BWHcIVfgP6lVyPnk/XVhZ7 +dT9oPs29aQKBgQCg2XF9yy+G3MpXcG+21v2yhhWNO+llP7HPu9K+UlxbhSpAptMz +Mf3MPim3TdTkbZ0j11dbrKVcF4y2qbZ63xSjUM6QNnqRh3ofuYpFIwo0juE/bsKw +o/j/xMY0Qg5YJz23BvH4qjDz0U8XYH3GCOYvyaa3GLzMoAXGtam8dxPttQKBgQC6 +dFJVKD9M5zp7JSD7sFejhr5CuwPP2bvWsrXPAdxjmq+lOmOn8C8yG1rMQckY4had +eYGjvJtaN9HFUtzFaDsGbqbq+TiE5m44MW1coasE6UH1FJspspNJgTH3QPiYQYMY +tFc5jTgbQfAuPoAvBGk+g2JdKJ9JB62k/RewA3NMqQKBgE0ViRuas9/p9t/8mvxs +wp3SBagnQX47PelfywYSTOLeIowF6yjopCg3By2mWMfq0+2KpkuI3c2Tg26R/9pL +JptMqggygFq/9D+6VVrkgMPevXLzu/1iyDsv8+Uw0xYvwtAX0ib3NGrG1EUEcWud +OTZibfBsbA3aJPz/z83kmniS -----END PRIVATE KEY----- diff --git a/src/certificates/order-command-api.pfx b/src/certificates/order-command-api.pfx index 3397b77..c9c74a1 100644 Binary files a/src/certificates/order-command-api.pfx and b/src/certificates/order-command-api.pfx differ diff --git a/src/certificates/order-query-event-api.crt b/src/certificates/order-query-event-api.crt index 1e20d60..26e2c43 100644 --- a/src/certificates/order-query-event-api.crt +++ b/src/certificates/order-query-event-api.crt @@ -1,29 +1,29 @@ -----BEGIN CERTIFICATE----- -MIIE8TCCAtmgAwIBAgIUAfT1chDFp31Leol2oRLutw0pce8wDQYJKoZIhvcNAQEL +MIIE8TCCAtmgAwIBAgIUAfT1chDFp31Leol2oRLutw0pchAwDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM3WhcNMjcw -MzE2MTA0MjM3WjAgMR4wHAYDVQQDDBVvcmRlci1xdWVyeS1ldmVudC1hcGkwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDfEF2wL7+kZFVdLYY7Y45k1YwD -ksTdMwbDBSCVe0X5spzGfXrIiMoTcOQuLodKKnZ8LoAvzJUjq6BrSlxtHWDxOL7/ -tEm241mHPhfoTW2wbZKiOUBQBntq4KnLbv5fSRIg327m2WbOK4KP7XfCiT10Ho1y -G1pDrCkiYjdLZGM3P498COLcH9AjuhRnohz5LwVSy1cMj/f7BGN9wSS43ydjBXDr -HLh5uzl745lNtHyGkTw0x17HYCYShP2tRFIungu8+f/l06tp5x0nqpjJA19oAZo/ -pmIe9GYzxZOf1cjKWVXNAok93rl3+cCWal6+ic+NdPQkrDQYRTXyT7OhM+dfAgMB +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQzWhcNMjcw +NjIzMTEzOTQzWjAgMR4wHAYDVQQDDBVvcmRlci1xdWVyeS1ldmVudC1hcGkwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8KvlsA4d0XlVxJdMWeP4uZZEw +Rwpc0z3WF+7HsnL6EJy+V7irnQMiV0PwMGag30nugUpZ6ngyAnT3R93QfUyvdBaL +YlWZtgAaKNZO7ZUXNLlluaG2Mz21uqZ43efSpH9++5JodU7XXt7RynHDISWYveph +5ALTvkH2eDajisQXL4kfMUUcg13os8J/wWtt5Kc9788enDRRu7mR19JVTvYSMsH/ +ri0C0iRzgB9AbWph9GC/w+X5WkbsSvyzIdF6kGKayW/gMry8m7C0ud6vleASidDp +1KcjTouMZjT0z89rX4nyq5NMvJUFmoFBpnx0kbp46RMgARSMXWPvyO94HB8FAgMB AAGjgfwwgfkwgZQGA1UdEQSBjDCBiYIPb3JkZXIucXVlcnkuYXBpgg9vcmRlci1x dWVyeS1hcGmCI29yZGVyLXF1ZXJ5LWFwaS5lc2hvcC1taWNyb3NlcnZpY2VzgjVv cmRlci1xdWVyeS1hcGkuZXNob3AtbWljcm9zZXJ2aWNlcy5zdmMuY2x1c3Rlci5s b2NhbIIJbG9jYWxob3N0MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcD -ATAdBgNVHQ4EFgQU1ECK6eUYame57RR212wK8+HXntwwHwYDVR0jBBgwFoAU8ees -wamMHHVWaxqeTxbj4FYlxgEwDQYJKoZIhvcNAQELBQADggIBAKb5V5b6Au3kJMPU -bdssU3lbD5wrU02toJjvJ/7KnCQUepzrmTt8EZvwAlPwguBipqrIH9dQ7d5JzUOH -+yFYUvfUlP/H1zwxGpmWe8mGY8fHf9nIDfNqhkNaZVP7xfUjb6xiMS978PW/7KAv -FsaI3UApzl6Lppe5DyuaoGN1Q8lzlz//4QARck+wVQzAuGSr1hMNt4uKK7cHcikJ -iSEpUsQsJp7NM5FXJSpkQsgJX0iCJMKz8BqnYr5CXOxgMa0FHyFo+t5iS4ShGq8I -cjONBVyYKcBXWhMM7yv6JyQumlm00GSmqOkZW+9iGRTfgF+UDjwe2CHDiz4hdqAf -hhLziXBGW5CZXyfcSJyLpeS1+vyNfnewhk2+cHQ33IKDUSFQbnrPimBQC1avf8/g -xIuA8Z2VQiy//gRlXOpy7OJbxcahHaZtIj1KojY2SlUduk5ycJP23rAr7u756fJZ -DbmwQYnlogb8A3ubzxqSHtatDcivdmLqsLQy94I0mUJwgbpQPjTFB20B4hwtfMFS -XPUV+0BA7HhwdnRwO4ouG8/rr3yXjKuFiJMj/aft76VhLOqARKEan2n9jkqQjtnT -nDBJqJbxSbnkmafFYGX3b6MnS92W+N7s3aLoyBr8Nw3IsRA1MRkS0uA0KOSPKN0i -0pNW+Bfyr41BkwvrLiqQgvdyZrbk +ATAdBgNVHQ4EFgQU1bHHMbC+suaVUJTbuwhzhzwDXecwHwYDVR0jBBgwFoAUvxJb +cntjIN5LksiV+L/gir0oLAgwDQYJKoZIhvcNAQELBQADggIBADad1CMGhD+bBDtK +QBuvTpWhiMsmhUPF65cMQbslIMKf6TG98bCCZz13Uj7Iul7pEMz8vtUIela6tuMW +Kzi0DP0iNPrQRQ9bDswGGyyYtzM6ghYyuzVm+8WspT6RIiIIhmjnFHHFkN7wGugK ++pb274Om1W1cMdJWjOiKyF2TiWVe6JSNn27Qj8ghHF90JS+BAwmqnfyushQQKJX0 +Nd/mcTJKm6JapNaADFkBuM3u4B4BT+exDrcwbIMXgMjE2WZ4E42lluCQ4GI3tVET +8b26MtzBQGks0seaaHEj2wMUzSDWciBnMH7YSObbWj2WBsitGd6c1/fvkVFWbA68 +YoPO+6Fe4c/FP3UI8MxOei5cexGzb6tCHI/duRRp3g/B7jSKQ3riCZrZmAXxL7sE +ZZPPEUMD/Q94YC0Cm/EntHaVcSVOSxKpbznCY5SAPbRXvqTdXhXU3IRjNfn9kBGP +q9DIAf1vohtGmKFh0CRsOt0XK80mvODY5iOSYpX4uP5AmURep+jSn6CgWE+CVSEg +DnRqFapN9AW1/u3XP2eAU6A8OPg2Ib1PDRYiI+NXrPE7nMrBjXTQA/jQ0vPit+te +7B4caOloq8wSKm8UJ0VDaDzO9vQPu/V1txezD8s8F/zun2O69HEHdaQm1UIW7s7g +UhukI2BgG/JFKkP3j17C6ubup/Ru -----END CERTIFICATE----- diff --git a/src/certificates/order-query-event-api.key b/src/certificates/order-query-event-api.key index 4ddb97f..27ca406 100644 --- a/src/certificates/order-query-event-api.key +++ b/src/certificates/order-query-event-api.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDfEF2wL7+kZFVd -LYY7Y45k1YwDksTdMwbDBSCVe0X5spzGfXrIiMoTcOQuLodKKnZ8LoAvzJUjq6Br -SlxtHWDxOL7/tEm241mHPhfoTW2wbZKiOUBQBntq4KnLbv5fSRIg327m2WbOK4KP -7XfCiT10Ho1yG1pDrCkiYjdLZGM3P498COLcH9AjuhRnohz5LwVSy1cMj/f7BGN9 -wSS43ydjBXDrHLh5uzl745lNtHyGkTw0x17HYCYShP2tRFIungu8+f/l06tp5x0n -qpjJA19oAZo/pmIe9GYzxZOf1cjKWVXNAok93rl3+cCWal6+ic+NdPQkrDQYRTXy -T7OhM+dfAgMBAAECggEAUKtlhnMuNnCGoqT1F4NAmtzTvvMUOP7cIik3iHfFbbEX -m30Dq4Q0uGUqUD1Jdhv3L5/NgfvVr8nAwSxqUpe+WF5yTJ1Rz09XMF7XXI6r7ZMi -5YIY7Rf7CELphQXF/oW5haPoQpo64LLBi/WQSw1A6T6nXq3frfuUALhOUPikHPU1 -mqsdRJT8mf5J7Ler3IEA4T0JAdl6Sb4TB6I4Vd4tHa9Lg/h9hxoDgmaW2S14dpHF -zpT/Dv7mS9leZYfY1oWw/fc6nRxXACVVLcbWpRH5oJdQLiupzZFhtZg4SDB4kgi+ -5L8ybfQd+4hvHGR5k9nJChddVOeWC7FUjPZaHYaNWQKBgQD5RTdeGTLxoxUlXaNA -l188+UsdY+/aI5M00t+UbY29ksxvqIWPa9feGcytMXBnERzp07Y6oTM7qS9+Vxmp -Z6aGQd/bxlEUu/DoNaB9jFXjmFixbR+RNOhvuS4J5EQ4duka1J5fKZ01Ne/R3+uJ -wccUt4NkVA3w6JozBE6xxH6fOwKBgQDlFgdoGSYUz7Md3MDo2EUtU+VdhSCbRh5R -VPGdV1WSbXDjadeS0wa++hKWnEHRxyF450C2tgxeT7eR562eyDbPopFC+oFugSeW -J8aB+rU1tH7PCNvHYpNf9sZD9o6KwgHXsNqOBXPMC/ac5/28aTkD6w4+yr5EXEtt -wC+oLkseLQKBgQDPGNucWVFDAtxBtB87PchJj1EB9RLEaIQYAg7xcWeulfU124xD -kTTC+SpcxlN9vfEIr/WZlm5LZg/oZpMSdOQcbUSAgq7AjDjlpBBX3q1JLzyZBHGS -oaNvlymR3E11oA2hVf7ST2+mUs6RzvkQ9abiJmmKhG8ktQvP0QdUmE0fGwKBgGUP -Hb9XcMw3gA3JZ7SQS5weaY2i/+pfuVopvdiqQU6yRt2bwIS94Tj4eqDEV+jiDqsW -YR75GmW0hwevi5EDQ+K/FZPVjKmiAkOkUlbesXf6owJUJxhDLT5lT7uFlgYyZbuw -Agoq75VxJZ68XNv0EzneRM+AgwUHLiNBaASqP2sVAoGATnwnFN2KqB7HuoH95Pzy -k3VbfGpqBnYAewUwwT0SQu4Vn4P0u0SwlJXgMHT44TDSZ+qRCoGsvEC6PaPlgCqa -oMM0otCTnO5dU3eq8Vo6BPwrKG710ThAQsX/tKW5F0BsBOGPvgV+3ssrYUyEbYrW -k3CBqDUpTNJuHdg3lPZeuX0= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8KvlsA4d0XlVx +JdMWeP4uZZEwRwpc0z3WF+7HsnL6EJy+V7irnQMiV0PwMGag30nugUpZ6ngyAnT3 +R93QfUyvdBaLYlWZtgAaKNZO7ZUXNLlluaG2Mz21uqZ43efSpH9++5JodU7XXt7R +ynHDISWYveph5ALTvkH2eDajisQXL4kfMUUcg13os8J/wWtt5Kc9788enDRRu7mR +19JVTvYSMsH/ri0C0iRzgB9AbWph9GC/w+X5WkbsSvyzIdF6kGKayW/gMry8m7C0 +ud6vleASidDp1KcjTouMZjT0z89rX4nyq5NMvJUFmoFBpnx0kbp46RMgARSMXWPv +yO94HB8FAgMBAAECggEAAIK5JQ6LmE7/09wHd95+fORx+BI4e4dOOgD1uRO2PxDH +xoN17cjlPu6Pyy/ScEbS2RayogGIvHgBvPPauZiRc/UKCtKxCuCYNpOPfoZwbfzx +MNu69HcTCIwRkuJLrgICX5DLghGP1A+x/2c/4+JSSz94SpydpL+PYPdM2XV3sg/O +uKTJK4kzcO2TaKRwfm4Cs5uSOJ55K/KTGqdpslPThmLr9ReoU5cqO1C8sEyltcIt +eviZ5PLSH7gAzqJFWR8xumsZvk5KLbnMwo3exA5Vd4W5uMu1P5bXSQOhgbQIUKhN +bC3sC75/yJea+xHwjZIajh7sck8xkR/TsWpz9XXaWQKBgQDcyY9ic+vguJVCO54n +hF7bDmJ8U+Iewn2jAIuiDOmaigNYVUy4k7CSohr4Y4yguO+FnJ1l20HutznK68X5 +R9d2NKWPJzUUfyZ3XS0fBPAjAcBhGrE9AaKdNZsGNjeu/BC2m9oxkgHyj/VTEbFF +lfwKNF2v6PzkKhQduQZZyOJY/QKBgQDaLZs+iK2wY7KiyTbcdm9enrbPGXiIQDlV +7sNfE+V2SW530s6JBUY+JO0ZR6GDDG2pVdgsj1r1C+7Tu0yc1SvcVNNlyZGB7eOl +y8+nFj5/4agxz9CoGjO0ZSonbSOUZOs/LXFDsb1mzuel+2PM13MtY70Fv9jTJ+1F +Sej7SbrgqQKBgQCYmrCCikE1OB/igbaU9cdifZTQ/mHChQe1zMC2p1onuNELExpO +UbawA1/E43nl9S2JGnEoX944k2hcu45A+MkSKN1uDtl/a0s5Iav4Tr90UteXxo1O +73xoUQ7vwjXGuu8KaLrtnE/ASoR0gDwZLsvgecVvuwhg5Dy3NpYPJOxeOQKBgQCW +PdWsCF7jGqSG6Nz4kC49EDp+/uE7ok5ZWKP9MyxOel6x8N79CD7IyJDlWahlIAfc +FhtZBBb0rBT4hQBK95jOjzNL4rRqrrCXGXSTcQP0+CXkt2DOgcydKxUONV/M7nn4 +9YgLv7fXth9a83RUOQE9fnNKJERhlBsWHcFsWedwkQKBgDjYIUTJcrBI1GnpQ93v +ckOHEx2FCshxvd75e0g5j6c43pnNHwfuTI5sBHfuivNZWEQMmLFbSe2zzBC4iRiN +I1L3fbu89FilkyzP/EdSTV1GFn4f7pGhpE/uM47t96e+10ETUjvVT7F6DVOX/UsI +vrS/Z9Jq94bmEH/jWVkT7N0T -----END PRIVATE KEY----- diff --git a/src/certificates/order-query-event-api.pfx b/src/certificates/order-query-event-api.pfx index b04cdcc..dc0c352 100644 Binary files a/src/certificates/order-query-event-api.pfx and b/src/certificates/order-query-event-api.pfx differ diff --git a/src/certificates/order-query-event-processor.crt b/src/certificates/order-query-event-processor.crt index 4acfef7..53401ea 100644 --- a/src/certificates/order-query-event-processor.crt +++ b/src/certificates/order-query-event-processor.crt @@ -1,30 +1,30 @@ -----BEGIN CERTIFICATE----- -MIIFJTCCAw2gAwIBAgIUAfT1chDFp31Leol2oRLutw0pcfAwDQYJKoZIhvcNAQEL +MIIFJTCCAw2gAwIBAgIUAfT1chDFp31Leol2oRLutw0pchEwDQYJKoZIhvcNAQEL BQAwRjEnMCUGA1UEAwweRXNob3BNaWNyb3NlcnZpY2VzIEludGVybmFsIENBMRsw -GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwMzE2MTA0MjM3WhcNMjcw -MzE2MTA0MjM3WjAmMSQwIgYDVQQDDBtvcmRlci1xdWVyeS1ldmVudC1wcm9jZXNz -b3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsIY3t/MJglNeDr/Gb -LzznSf1uustWg1dW6Wv1wbBNgIUWHmXUOAR7LT9OO6gSZZnGGeqAdWHKkomy3RhQ -/nrY0RpyfZPvzqB1DMdKZjdmHM/UlWNx+ljlpSuEP+OGJL43M4irGYl2I5l8IKRP -+/tC6RPAwmuZLJR2MsCMUNfk8k25qka67Qj9xyiv1sICH5an7VTBmbOD7vU8Jex8 -/hd/+KxKgYiLq1BPFDSGoH9KgP5nPt6K5saJ6cyfH59h8WtiAx1W4scfzJ+FnfE7 -DyyC4gYYWkTQXbej1HLRFqzpJ9EfKpXzvJ8MwPwzoFUNFak4/IfpIBQ4yT1s/WUk -ENyDAgMBAAGjggEpMIIBJTCBwAYDVR0RBIG4MIG1ghpvcmRlci5xdWVyeS5ldmVu +GQYDVQQKDBJFc2hvcE1pY3Jvc2VydmljZXMwHhcNMjYwNjIzMTEzOTQzWhcNMjcw +NjIzMTEzOTQzWjAmMSQwIgYDVQQDDBtvcmRlci1xdWVyeS1ldmVudC1wcm9jZXNz +b3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl2JfgFgX9LThdRJ52 +fGktHUZhBq0t9o704ne7KGSD6iq43q3T/QEmMPkFPqbUrEbZPmWB99XnpUKDGMVp +bFjM9BAaK3RcJetv86DTRnOIi6IZh/T9XbyDbmgguhtg0KG3UbSlEKrc8b0uaApJ +Eue0rWoiwOGytH+P9yM4G75WdhjKCa4VN24bqSkgTg+dUeHZE5WSpERKBSU2FHSt +7ctYQ8Yy/dUr6y5Kjuc5bOKer3s4e+9Mk2WBm9Fp2lGMAE22fTSH/2i/DAWb/DJa +SLz9tWdLYs9wZq9oiP+0ALAMVAhdo1rjNLCXxPwexTuDxZbpAvCU+yEwAdz6FTLe +AbtnAgMBAAGjggEpMIIBJTCBwAYDVR0RBIG4MIG1ghpvcmRlci5xdWVyeS5ldmVu dHByb2Nlc3NvcoIab3JkZXItcXVlcnktZXZlbnRwcm9jZXNzb3KCLm9yZGVyLXF1 ZXJ5LWV2ZW50cHJvY2Vzc29yLmVzaG9wLW1pY3Jvc2VydmljZXOCQG9yZGVyLXF1 ZXJ5LWV2ZW50cHJvY2Vzc29yLmVzaG9wLW1pY3Jvc2VydmljZXMuc3ZjLmNsdXN0 ZXIubG9jYWyCCWxvY2FsaG9zdDALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYB -BQUHAwEwHQYDVR0OBBYEFP2BgNEZwqjOHjh0k6Hvi5bRgkF/MB8GA1UdIwQYMBaA -FPHnrMGpjBx1Vmsank8W4+BWJcYBMA0GCSqGSIb3DQEBCwUAA4ICAQAzi7W6dPzU -osoBcG9ts8zf5zrg1fl5QYNd13xjZni1txv4+rAVMyRdQ0Q3d/P4BvSItqrkgdsd -gWpsQ5qy8pq4YUXqbha9RgxrQ4D8GNkT86Uy1Wq8OOu4Vv/BId+iRkP060SC2keO -f+9El00221O2jzIv1puZzGtJptRuOh+bqtJrjAUyQQrS0nfe8Ob7AATIK305HgwN -T7IDbjPLxOwfG12orNTkIR02KTckoyLOhDfinZUs6Ls2sOe3eRsaQYQcVfrGRv+7 -QhILweYGEv3V1dLGnWc2tkmJUvO27fAk0N2t0u9IpvPEJonRdrFdBRbeDmM7RGJ1 -V36xsCyvJy6BONB+bPfdF0Tso1IY+t17+TMP+oyPVNeT0QhXJx48UFlAbvb6fDr9 -eUaZ3GVnjpAWWNRcJcJj/8PR3GjZv4lW0aME4jcL+rE5llaQ9Q8AQGK+umbNEAou -E26hWUJ7oEhQiK8mlmJsqMS94fEvoJvSaPQ+uMUp53A5wpdffSVll+qg4rOlvNqE -SErvG1axr6suoYm1AGHTjExMTRFZYiS7V17PTf6i7SsQVYfxclUUZq6OVuKqMUOZ -ihbTA+/xYEmzPEiwhMRPoK0qRUMa6BGqPm1RHX0ttqFCeSNjYfJDOfCgqOhOzl4o -q7UJpEFQ7z3woojpFVmODTNwP3kYncKM1Q== +BQUHAwEwHQYDVR0OBBYEFF0VPGuHwQ1gBIf5UVZoLQkg7scgMB8GA1UdIwQYMBaA +FL8SW3J7YyDeS5LIlfi/4Iq9KCwIMA0GCSqGSIb3DQEBCwUAA4ICAQBOXSVTrG7c +nZ6iaaSah1aHl0V68gLZLOL03uUcq1HWfx30WU/PgMjyyF4Q+0Jx4E4ooviXSLC4 +lHvJ869Si3urVGmy5NFeimL7KyAUAeHxNt3jcTNWrWXj8RBnnoT1WUmH5x6VBQfn +s2Gx+mC+nHgfoWsoEhUeGGSyoQegbdzNStUy7oKD/YgDbIaHUDpSHN+6Tu7HRRSt +UogV4NcGvCDJoZ1cEH2ZLx667DZ+VLT20vaHOarGda6sal42JJAFwXLMvjjQ7UKp +a59E1jV9n2SMcEWKJsZei8RZg2kjPXQGrQUkX8pRxDROEIBbdflnUqi4PQ4/iz2V +Aasc1zWostOBkncx5+oCe8DA7ZWXRLmaXY2DjOwva9nJXW1w9d1uIBr0N2H3FYxH +PR12Y1qM0A4iAaV1r0hSMOcno83Vx8qcbjSWYmxXdVMT+hORXyy5qzOL95yiaoXL +QaT6NBlY7vxkUtN3a8PLp4OqVzArBE/8rWn0fWkOAIW6G+CPdyx261vbwr4qrCAh +5guRJSu5viopZftsfOc3RmMjplzvqF9ywAFzbvK8ZKfGa79rWzCrEpr0RhbeH1lv +C0ptxYOkETqal5PqUA6MgxW4Ofb9wucXpqTInp8cKOAbxQUNrSQpLQZRvPpD/0mc +vwPeAhSE811NVvJcATYDQgZk3Wflj7h1DQ== -----END CERTIFICATE----- diff --git a/src/certificates/order-query-event-processor.key b/src/certificates/order-query-event-processor.key index f45e4ec..e1910f3 100644 --- a/src/certificates/order-query-event-processor.key +++ b/src/certificates/order-query-event-processor.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsIY3t/MJglNeD -r/GbLzznSf1uustWg1dW6Wv1wbBNgIUWHmXUOAR7LT9OO6gSZZnGGeqAdWHKkomy -3RhQ/nrY0RpyfZPvzqB1DMdKZjdmHM/UlWNx+ljlpSuEP+OGJL43M4irGYl2I5l8 -IKRP+/tC6RPAwmuZLJR2MsCMUNfk8k25qka67Qj9xyiv1sICH5an7VTBmbOD7vU8 -Jex8/hd/+KxKgYiLq1BPFDSGoH9KgP5nPt6K5saJ6cyfH59h8WtiAx1W4scfzJ+F -nfE7DyyC4gYYWkTQXbej1HLRFqzpJ9EfKpXzvJ8MwPwzoFUNFak4/IfpIBQ4yT1s -/WUkENyDAgMBAAECggEADNM3Mvs5NF8Cq8IpO0nKvOTraBus2NZSZJxhud7jlvKz -d9Ft/uDpnI/jfp29SRme2n7F1SppzeEbN2N301kSqCL0WIF4y05W8EGye52gFRCi -f5Fd5nkjtICY/HKSLkWAkrZZQX5WmqHOZsw70eXRc8vP9/XEdJY4vZHMfOftHha8 -YMgsqsHJ3v/6gXRNUOP0diPtm7qxNwbhtMr/fFK3QhtbJDhzUszDawmyGvFWVv8Z -y2StPfK4wze23x0hsJbSwmFpgouMrSAV3tka/OgqbgPwfQEO39JsAOQ9Fpp22K2P -MJglAYT4Tg+5iMwm+/IRYF0AskbGhNq45Lz1LuKpOQKBgQDVPd331m9vE2+j1XT6 -ppbh9kdBIEv9CGnEIzdoADenhkJyEKNPBMvuBZx2N1nSBBta7ttz6FxhlB/tGrYO -T3GjYdYQIwTq46Q0QfEhMW2Fy1V51POnkLxNZMJ15bp9DOFaK5rozxIyz6h9tw6v -oC7OeMAVwfc5NpA4PY+NatZmbwKBgQDOpWVe8FCw47EJkzJKyAsSo0NsMme4LMUq -nRAOWl9jZv1OHjVG71rJAGD7kChBJ0jrbSTxZDUBnVHPpBP2y3yDNMBFkEq9NyMt -Mcx8raq0E4nmcLirJd+aM1BgfHLPzp9+BV5qhsHrUc1+F5yCjnPCxO9FQtDyTjqb -NOOmWIJVLQKBgQCo7cAAbKIOrqkMczeesYZqL742+6z3IUkYloV4IGP2lMfisQeO -u9AKGevfQu4nEBXTrdGwOu2kZ8H7BeQf5hOySPlaA0QMCJa2x16M2ylWisSGJYt4 -vZJPBXmACKP6GNAVrOGleRWDpzpljTVXMGCkNMiG9Ag0DOOnii1E7NQ4hQKBgFaM -zaVy78j2xLqm7SSHHqQiv2V8wxZPohEUEZqBXXxrsWJboqLgM10GjJgwq7uGMbNx -VkzIVK8lbhOSvE3csnzdxj4cjkEr687NEcGSl3Gu0U40HhSI21thbKPM2+WPvBtz -MjVZ1bSy4WeTihjggzmrdC/FKXCjNUa2YzbT0VrNAoGBALTOdBvA7tCG3y52XcZ0 -S44ua6uLLUVP8dzVCh4esa2OVYEH1/bMCkL4UFj2LCVYxsjsXS5+fSMYD+Sv+6Nh -xxAbzekTNh7wm8YTxGSaNt73jjSHo+8BcmFbh3pg0KZJypYXdjz/6aZUqD0NEtz3 -/4BEev/6oDyrWE+0gIlXbSuL +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDl2JfgFgX9LThd +RJ52fGktHUZhBq0t9o704ne7KGSD6iq43q3T/QEmMPkFPqbUrEbZPmWB99XnpUKD +GMVpbFjM9BAaK3RcJetv86DTRnOIi6IZh/T9XbyDbmgguhtg0KG3UbSlEKrc8b0u +aApJEue0rWoiwOGytH+P9yM4G75WdhjKCa4VN24bqSkgTg+dUeHZE5WSpERKBSU2 +FHSt7ctYQ8Yy/dUr6y5Kjuc5bOKer3s4e+9Mk2WBm9Fp2lGMAE22fTSH/2i/DAWb +/DJaSLz9tWdLYs9wZq9oiP+0ALAMVAhdo1rjNLCXxPwexTuDxZbpAvCU+yEwAdz6 +FTLeAbtnAgMBAAECggEAKoIOwJZCIEszL+inZ+FlcD8IS5x4/dWqJbcWjqoPQOhX +Y15nhpu1kTMgcuxd3VpJNhdYnZtQ16kULnuv0uoDWFBRBA4CVKJ8svU7SqeuaVPt +tEwVLqCd4y7Rmi/hLVwYdHdrcdWty/P3WXRLZq1U5fDmfqvuceb46o652EAlSQbv +lX+sJeSo5K3aVvUvwgVZaTIj+uM8Wd9yc6UMPneBAEEKK63jkn0a5kh4bqO1aiUv +64effCk9tUbb/fLdGza0OFseY4iX9xkWD2lYXLp1COt7RrKJWVx+ArRiutAZoylw +yxMB1/ovKywodUx4kDFiLIiLUvoP6DXxsRvuE7/yXQKBgQD6JRJTLhgjYI/iVfc/ +UX1m9oT3dsrJBgeXr6Mu07Uta2KK7sj484qct/mc4EPJ1Li2DLkCb/lQaBew13Wv +ZjNupfxqgIHG0T4b22xHnR1nWGiCrEU3/C04Ffnp1mlG9u6t2BUoMo35sliW8Tlz +BkpnlM7ENB2FBGZ1YIAE4fgQswKBgQDrOeL9uZ7eZJIEBQNsJT0+KRRwJfuxYDva +iAFlYCVNXQsVuANTW29K4dUy4VjqB5KMbJTkJKmsM136Ai4pGaYlnmNvoIvTdvmk +KxbStkQ1toY+X1rB+9jpvh78Xjkwjr8RKCE+7h0LCSHt9cF57R5e0mCi9pCavSgb +G7VHrLocfQKBgQDz7GCBMkqhfNDx8chHO0ygsbWZpoI6IqIWvVPQHuvmnXebaRwa +/0nkZtaGrn4L+14fUCq9ALnKOacYcBI3dt6igEOzCxsB6Bq7iW1+K+x3UVOgUSKy +ZDsoHO31o3pHlBXM+hAvgZTGr64JirLtwm2dshMqanN6uX676N0NZdjDVwKBgQC9 +lBrYqMhcrqtr5+p5N44jUhJxzHsM2uWCW8jcPl/x+QIdEABGJ1QMAvTEHBCAFXhM +Cpr5QH8rFP8xpp4za8OXYA7+AWOQG7xZTo0HZ/STYbbSACHyY5rPz/XDKeFnvDRL +jI8228u2gDbDRSUYsj2e6GkQDi4/OCJhrrQsvw4ENQKBgQDkgsK6bmglzOhm65H1 +0TFU6nxL7c2D58+y4N9GJzx3tblEPMsX1EHQTYjIeXnoJe0l/l00yOA0HzzldfGs +VktK9kPk3IB4y/lEknDSK27ICnr8w2lvVekDNhsdvaQhxq6ERk7+4zZmkB4jm0Ys +UgpJoDtXjjH1h2htD3A6Qgl00g== -----END PRIVATE KEY----- diff --git a/src/certificates/order-query-event-processor.pfx b/src/certificates/order-query-event-processor.pfx index 1ffd05f..313e707 100644 Binary files a/src/certificates/order-query-event-processor.pfx and b/src/certificates/order-query-event-processor.pfx differ diff --git a/src/eshop-microservices.sln b/src/eshop-microservices.sln index c222bce..fdde7c8 100644 --- a/src/eshop-microservices.sln +++ b/src/eshop-microservices.sln @@ -42,12 +42,12 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{4676C07F-D243-48AB-AF97-20C6B606F9DD}" ProjectSection(SolutionItems) = preProject Directory.Packages.props = Directory.Packages.props - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{EE1AEE7A-1B5B-4AC0-86D3-BE61806979CE}" ProjectSection(SolutionItems) = preProject ..\README.md = ..\README.md + ..\docs\k8s-guide.md = ..\docs\k8s-guide.md EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Order.Command.API.IntegrationTests", "Services\Order.Command\Order.Command.API.IntegrationTests\Order.Command.API.IntegrationTests.csproj", "{73EE7B5B-F93F-4270-87C1-D123FD9EE4D8}"