linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • Симулятор
  • База знаний
  • Собеседование
Index
Categories
All entries
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
home/linux/kb/Безопасность/tls-certificates

kb/security ── Безопасность ── intermediate

TLS-сертификаты - X.509, цепочка доверия, Let's Encrypt

TLS cert - X.509 объект с public key + identity (CN/SAN) + подписью CA. Цепочка: leaf → intermediate → root (доверенный OS). Let's Encrypt = бесплатный CA через ACME (HTTP-01/DNS-01 challenge). В k8s - cert-manager.

view as markdownaka: x509, certificates, lets-encrypt, certbot, cert-manager, acme

Зачем TLS-сертификаты

[[tls-handshake|TLS]] нужен для двух целей: encryption трафика и server authentication (вы общаетесь с настоящим bank.com, не с MITM). Аутентификация, на сертификатах.

Сертификат, это публичный ключ + identity (доменное имя)

  • подпись доверенного третьего лица (CA, Certificate Authority). Браузер доверяет CA → доверяет подписанному CA сертификату → доверяет серверу с этим сертификатом.

Без сертификатов TLS-encryption ещё работает (anonymous DH), но вы не знаете, с кем шифруетесь.

X.509, формат

Стандарт ITU-T от 1988-го, в 2026-м всё ещё актуален. Сертификат ASN.1 DER blob, обычно в Base64-обёртке (PEM).

Структура поля:

Certificate
  ├── tbsCertificate (to-be-signed)
  │   ├── version (v3 = 0x02)
  │   ├── serialNumber
  │   ├── signatureAlgorithm
  │   ├── issuer (CN, O, C, кто подписал)
  │   ├── validity (notBefore, notAfter)
  │   ├── subject (CN, O, C, кому выдан)
  │   ├── subjectPublicKeyInfo (publicKey + algorithm)
  │   └── extensions
  │       ├── SubjectAlternativeName (DNS:*.example.com, IP:1.2.3.4)
  │       ├── KeyUsage (digitalSignature, keyEncipherment)
  │       ├── ExtendedKeyUsage (serverAuth, clientAuth)
  │       ├── BasicConstraints (CA:TRUE/FALSE)
  │       └── AuthorityInfoAccess (OCSP, caIssuers URL)
  ├── signatureAlgorithm
  └── signature

Расшифровать локально:

bash
openssl x509 -in cert.pem -text -noout
# из живого сервера
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -text -noout

Где живёт identity, CN vs SAN

Раньше identity сервера была в CN (Common Name). С 2017 (RFC 6125, Chrome 58+) CN игнорируется, identity берётся только из SAN (Subject Alternative Name).

X509v3 Subject Alternative Name:
    DNS:example.com, DNS:www.example.com, DNS:*.api.example.com

Wildcard *.example.com матчит foo.example.com но не bar.foo.example.com (только один уровень). Wildcard на root (*.com) запрещён.

Если cert без SAN, браузер скажет NET::ERR_CERT_COMMON_NAME_INVALID даже если CN правильный.

Цепочка доверия

Root CA (self-signed, в OS truststore)
      │ подписывает
      ▼
Intermediate CA (в bundle сервера)
      │ подписывает
      ▼
Leaf certificate (для example.com)

Сервер должен отдать leaf + intermediate (root уже у клиента). Если intermediate не отдаётся, unable to get local issuer certificate на старых клиентах. nginx:

nginx
ssl_certificate     /etc/ssl/fullchain.pem;   # leaf + intermediates
ssl_certificate_key /etc/ssl/privkey.pem;

Проверить цепочку:

bash
openssl s_client -connect example.com:443 -showcerts
curl https://example.com -v   # покажет subject и issuer

Truststore OS, в /etc/ssl/certs/ca-certificates.crt (Debian), /etc/pki/tls/certs/ca-bundle.crt (RHEL). Браузеры, свой truststore (Mozilla NSS).

Let's Encrypt, бесплатный публичный CA

С 2016 покрывает 80%+ всех публичных HTTPS. Доверен браузерами и OS.

Особенности:

  • Бесплатно, без лимита на количество доменов
  • Срок 90 дней (вместо 1-2 лет у платных), стимул автоматизировать
  • ACME-протокол (RFC 8555), стандартный, не Let's-Encrypt-only
  • Rate-limit 50 certs / domain / week (есть staging без лимита)
  • Подписывает через intermediate R10/R11 (RSA) или E5/E6 (ECDSA)

ACME challenges, как доказать владение

Перед выпуском cert ACME-сервер хочет proof'а, что вы владеете доменом. Два основных challenge'а:

HTTP-01:

Запрос: положи "challenge-token" в http://example.com/.well-known/acme-challenge/<key>
Сервер LE проверяет HTTP, видит token → выдаёт cert
  • Работает только для одиночных доменов (не wildcard)
  • Требует open 80 на сервере с domain'ом

DNS-01:

Запрос: создай TXT-запись _acme-challenge.example.com = <token>
Сервер LE проверяет DNS → выдаёт cert
  • Работает для wildcard (*.example.com)
  • Требует API DNS-провайдера (Route53, Cloudflare, DigitalOcean)
  • Можно делать на любом сервере, не где работает домен

certbot, стандартный клиент

bash
# standalone (certbot сам поднимет :80)
sudo certbot certonly --standalone -d example.com -d www.example.com
# nginx-плагин (модифицирует конфиг nginx)
sudo certbot --nginx -d example.com
# webroot (если у вас уже есть webserver)
sudo certbot certonly --webroot -w /var/www/html -d example.com
# DNS-01 для wildcard через Cloudflare
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials ~/.cf-creds.ini \
  -d example.com -d '*.example.com'
# автообновление (ставится в systemd timer)
systemctl list-timers | grep certbot

Cert хранится в /etc/letsencrypt/live/<domain>/:

  • fullchain.pem, leaf + intermediate (для nginx ssl_certificate)
  • privkey.pem, приватный ключ (chmod 600!)
  • cert.pem, только leaf
  • chain.pem, только intermediate

Hooks для перезапуска сервиса:

bash
certbot renew --deploy-hook "systemctl reload nginx"

cert-manager, для Kubernetes

Контроллер k8s, выдающий cert'ы как ресурсы. Поддерживает Let's Encrypt, HashiCorp Vault, Venafi, self-signed.

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata: { name: letsencrypt-prod }
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef: { name: letsencrypt-prod-account-key }
    solvers:
    - http01:
        ingress: { class: nginx }
    - dns01:
        cloudflare:
          apiTokenSecretRef: { name: cf-api-token, key: api-token }
        selector:
          dnsZones: ["example.com"]
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata: { name: api-tls }
spec:
  secretName: api-tls                  # k8s Secret куда положить
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - api.example.com
  - "*.api.example.com"

Но в 95% случаев используют annotation на Ingress:

yaml
annotations:
  cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts: [api.example.com]
    secretName: api-tls

cert-manager сам создаст Certificate, дойдёт challenge, положит cert в Secret, который Ingress подцепит.

Частный (internal) CA

Для intra-org (microservices, mTLS) часто нужен свой CA. Опции:

  • OpenSSL руками, для одноразовых случаев
  • smallstep / step-ca, небольшая утилита, простой бутстрап
  • HashiCorp Vault PKI engine, на больших масштабах
  • cfssl (Cloudflare), быстрый CLI
  • k8s самоподписные через cert-manager (SelfSigned issuer)

Базовая последовательность вручную:

bash
# Root CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -key ca.key -sha256 -days 3650 -out ca.crt \
  -subj "/CN=My Internal CA"
# Server cert
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
  -subj "/CN=internal.example.com"
cat > san.cnf <<EOF
subjectAltName = DNS:internal.example.com,DNS:internal.local
EOF
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -days 365 -sha256 -extfile san.cnf -out server.crt

ca.crt распространить по серверам в truststore (update-ca-certificates).

Certificate Transparency

Все публичные CA обязаны публиковать выдаваемые cert'ы в CT-логах. Хорошо для безопасности (узнаешь о подделке), и для recon, поиск поддоменов по crt.sh:

https://crt.sh/?q=%25.example.com

OCSP и revocation

Если cert украли, надо отозвать. Старая CRL (Certificate Revocation List), медленная, толстая. Современная: OCSP (Online Certificate Status Protocol), клиент спрашивает CA «жив ли cert?», или OCSP stapling, сервер прикладывает свежий OCSP-response к TLS-handshake'у, экономит RTT.

В Let's Encrypt OCSP-stapling включается на nginx:

nginx
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/.../chain.pem;
resolver 1.1.1.1 8.8.8.8 valid=300s;

Когда что-то пошло не так

  • SSL_ERROR_BAD_CERT_DOMAIN / NET::ERR_CERT_COMMON_NAME_INVALID нет SAN или SAN не матчит host. Регенерь cert с правильным SAN.
  • unable to get local issuer certificate, server не отдаёт intermediate. Используй fullchain.pem, не просто cert.pem.
  • certificate has expired, забыл renewal. certbot renew --dry-run проверь cron/systemd timer.
  • renew падает с rate limit, Let's Encrypt 5 cert/week/domain при --cert-name совпадениях. Используй staging для тестов (--server https://acme-staging-v02.api.letsencrypt.org/directory).
  • DNS-01 fail, token TTL слишком высокий. Уменьшить TTL DNS записей до 60s, или использовать DNS provider plugin.
  • cert-manager Certificate stuck, kubectl describe cert → kubectl describe order → kubectl describe challenge. Чаще всего: ACME http-01 challenge не достижим извне, или DNS provider не настроен.
  • x509: certificate signed by unknown authority в Go-приложении intermediate не в truststore приложения. Распространи ca.crt либо InsecureSkipVerify (но плохо).
  • mTLS не работает, клиент не знает CA сервера или vice versa. openssl s_client -CAfile ca.crt -cert client.crt -key client.key для пошаговой отладки.

§ команды

bash
openssl x509 -in cert.pem -text -noout

Распарсить cert и показать все поля - SAN, validity, issuer, key usage

bash
openssl s_client -connect example.com:443 -servername example.com -showcerts

Скачать живую цепочку с сервера - проверка intermediate, SNI работает

bash
certbot certonly --standalone -d example.com

Получить cert standalone-режимом (certbot слушает :80) - быстрая проверка

bash
certbot renew --dry-run

Проверить, что renewal сработает - без реального запроса в LE

bash
openssl req -x509 -newkey rsa:4096 -nodes -days 365 -keyout key.pem -out cert.pem -subj '/CN=test'

Самоподписанный cert одной командой - для локальной разработки

bash
kubectl get certificate -A

Все Certificate-ресурсы cert-manager в кластере с состоянием Ready

bash
openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crt

Проверить, что цепочка валидируется против системного truststore

§ см. также

  • tls-handshakeTLS handshakeTLS - слой шифрования поверх TCP. Перед передачей данных стороны делают handshake: обмениваются ключами, проверяют сертификат, выбирают cipher.
  • grpc-basicsgRPC - HTTP/2 + Protobuf RPC frameworkgRPC = HTTP/2 + Protocol Buffers + кодогенерация. Четыре типа RPC: unary (как REST), server-stream, client-stream, bidirectional. Сильная типизация, бинарный wire format, multi-language. grpcurl как curl для gRPC.
  • mqttMQTT - publish/subscribe для IoT и mobile pushMQTT - lightweight pub/sub поверх TCP. Topics с wildcards, QoS 0/1/2, retained messages, last will. Малый overhead (2 байта min header). Брокер обязателен (mosquitto/EMQX/HiveMQ). Применение: IoT, telemetry, mobile push.
  • openvpnOpenVPN - TLS-based VPNOpenVPN - userspace TLS-VPN на сертификатах X.509. Режимы: tun (L3, default) или tap (L2). Поддерживает UDP/TCP, push routes, per-user-аутентификацию, TCP-443 как маскировку. Жирнее [[wireguard|WG]].
  • smtp-mtaSMTP и MTA - доставка emailSMTP - текстовый протокол доставки почты. 25/tcp - server-to-server, 587 - submission (клиент с auth), 465 - implicit-TLS legacy. MX-запись в DNS, STARTTLS+SPF+DKIM+DMARC - стандартный набор.
  • image-signing-cosignCosign и подпись container images (sigstore)cosign подписывает container images. Sigstore = ekosistema: rekor (transparency log), fulcio (CA для keyless OIDC). Подписи хранятся как OCI-объекты рядом с image. Verify - часть admission control в k8s через policy-controller или Kyverno.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки