certs.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Package providercerts manages TLS certificates for external secrets providers.
  14. package providercerts
  15. import (
  16. "context"
  17. "crypto/rand"
  18. "crypto/rsa"
  19. "crypto/x509"
  20. "crypto/x509/pkix"
  21. "encoding/pem"
  22. "fmt"
  23. "math/big"
  24. "slices"
  25. "time"
  26. corev1 "k8s.io/api/core/v1"
  27. apierrors "k8s.io/apimachinery/pkg/api/errors"
  28. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  29. "k8s.io/apimachinery/pkg/types"
  30. )
  31. const (
  32. caCertName = "ca.crt"
  33. caKeyName = "ca.key"
  34. certName = "tls.crt"
  35. keyName = "tls.key"
  36. clientCertName = "client.crt"
  37. clientKeyName = "client.key"
  38. // we're using a fixed secret name for the provider certificates
  39. // otherwise we would need to introduce a lot of complexity to the core controller
  40. // because we would have to maintain a mapping of provider names (aws) to provider kinds (parameterstore, generators etc.)
  41. providerSecretName = "external-secrets-provider-tls"
  42. // certValidityDuration is the validity period for generated certificates (10 years).
  43. certValidityDuration = 87600 * time.Hour
  44. errGeneratePrivateKey = "failed to generate private key: %w"
  45. )
  46. // ProviderCertConfig defines configuration for a single provider's certificates.
  47. type ProviderCertConfig struct {
  48. Namespace string // Namespace where provider is deployed
  49. ServiceNames []string // Service names for DNS SANs
  50. }
  51. // ProviderCertificates holds the generated certificates for a provider.
  52. type ProviderCertificates struct {
  53. ServerCert []byte
  54. ServerKey []byte
  55. ClientCert []byte
  56. ClientKey []byte
  57. }
  58. // KeyPairArtifacts holds a certificate and private key.
  59. type KeyPairArtifacts struct {
  60. Cert *x509.Certificate
  61. Key *rsa.PrivateKey
  62. CertPEM []byte
  63. KeyPEM []byte
  64. }
  65. // ReconcileProviderCert ensures provider certificates exist and are valid.
  66. func (r *ProviderCertReconciler) ReconcileProviderCert(ctx context.Context, config *ProviderCertConfig) error {
  67. if config == nil {
  68. return nil
  69. }
  70. log := r.Log.WithValues("secret", providerSecretName, "namespace", config.Namespace)
  71. // Get or create the secret
  72. secretName := types.NamespacedName{
  73. Name: providerSecretName,
  74. Namespace: config.Namespace,
  75. }
  76. var secret corev1.Secret
  77. err := r.Get(ctx, secretName, &secret)
  78. if err != nil {
  79. if !apierrors.IsNotFound(err) {
  80. return fmt.Errorf("failed to get provider secret: %w", err)
  81. }
  82. // Secret doesn't exist, create it
  83. log.Info("creating provider certificate secret")
  84. secret = corev1.Secret{
  85. ObjectMeta: metav1.ObjectMeta{
  86. Name: providerSecretName,
  87. Namespace: config.Namespace,
  88. Labels: map[string]string{
  89. "app.kubernetes.io/managed-by": "external-secrets",
  90. "app.kubernetes.io/component": "provider-certificates",
  91. },
  92. },
  93. Type: corev1.SecretTypeTLS,
  94. }
  95. }
  96. // Check if certificates need refresh
  97. needRefresh := r.needProviderCertRefresh(&secret, config)
  98. if needRefresh {
  99. log.Info("refreshing provider certificates")
  100. if err := r.refreshProviderCerts(&secret, config); err != nil {
  101. return fmt.Errorf("failed to refresh provider certificates: %w", err)
  102. }
  103. // Create or update the secret
  104. if secret.UID == "" {
  105. if err := r.Create(ctx, &secret); err != nil {
  106. return fmt.Errorf("failed to create provider secret: %w", err)
  107. }
  108. log.Info("created provider certificate secret")
  109. } else {
  110. if err := r.Update(ctx, &secret); err != nil {
  111. return fmt.Errorf("failed to update provider secret: %w", err)
  112. }
  113. log.Info("updated provider certificate secret")
  114. }
  115. }
  116. return nil
  117. }
  118. // needProviderCertRefresh checks if provider certificates need to be refreshed.
  119. func (r *ProviderCertReconciler) needProviderCertRefresh(secret *corev1.Secret, config *ProviderCertConfig) bool {
  120. // If secret has no data, we need to generate certificates
  121. if secret.Data == nil {
  122. return true
  123. }
  124. // Check if all required keys exist
  125. requiredKeys := []string{caCertName, caKeyName, certName, keyName, clientCertName, clientKeyName}
  126. for _, key := range requiredKeys {
  127. if _, ok := secret.Data[key]; !ok {
  128. return true
  129. }
  130. }
  131. // Validate CA certificate
  132. if !r.validCACert(secret.Data[caCertName], secret.Data[caKeyName]) {
  133. return true
  134. }
  135. // Validate server certificate
  136. dnsNames := r.getProviderDNSNames(config)
  137. if !r.validProviderCert(secret.Data[caCertName], secret.Data[certName], secret.Data[keyName], dnsNames) {
  138. return true
  139. }
  140. // Validate client certificate
  141. if !r.validProviderClientCert(secret.Data[caCertName], secret.Data[clientCertName], secret.Data[clientKeyName]) {
  142. return true
  143. }
  144. return false
  145. }
  146. // refreshProviderCerts generates new certificates for the provider.
  147. func (r *ProviderCertReconciler) refreshProviderCerts(secret *corev1.Secret, config *ProviderCertConfig) error {
  148. now := time.Now()
  149. begin := now.Add(-1 * time.Hour)
  150. end := now.Add(certValidityDuration)
  151. // Check if we need to generate a new CA or reuse existing
  152. var caArtifacts *KeyPairArtifacts
  153. var err error
  154. if secret.Data != nil && r.validCACert(secret.Data[caCertName], secret.Data[caKeyName]) {
  155. // Reuse existing CA
  156. caArtifacts, err = buildArtifactsFromSecret(secret)
  157. if err != nil {
  158. return fmt.Errorf("failed to load existing CA: %w", err)
  159. }
  160. } else {
  161. // Generate new CA
  162. caArtifacts, err = r.createCACert(begin, end)
  163. if err != nil {
  164. return fmt.Errorf("failed to create CA certificate: %w", err)
  165. }
  166. }
  167. // Generate server certificate
  168. serverCert, serverKey, err := r.createProviderServerCert(caArtifacts, config, begin, end)
  169. if err != nil {
  170. return fmt.Errorf("failed to create server certificate: %w", err)
  171. }
  172. // Generate client certificate
  173. clientCert, clientKey, err := r.createProviderClientCert(caArtifacts, begin, end)
  174. if err != nil {
  175. return fmt.Errorf("failed to create client certificate: %w", err)
  176. }
  177. // Populate secret
  178. if secret.Data == nil {
  179. secret.Data = make(map[string][]byte)
  180. }
  181. secret.Data[caCertName] = caArtifacts.CertPEM
  182. secret.Data[caKeyName] = caArtifacts.KeyPEM
  183. secret.Data[certName] = serverCert
  184. secret.Data[keyName] = serverKey
  185. secret.Data[clientCertName] = clientCert
  186. secret.Data[clientKeyName] = clientKey
  187. return nil
  188. }
  189. // createCACert creates a new CA certificate.
  190. func (r *ProviderCertReconciler) createCACert(begin, end time.Time) (*KeyPairArtifacts, error) {
  191. template := &x509.Certificate{
  192. SerialNumber: big.NewInt(0),
  193. Subject: pkix.Name{
  194. CommonName: r.CAName,
  195. Organization: []string{r.CAOrganization},
  196. },
  197. DNSNames: []string{r.CAName},
  198. NotBefore: begin,
  199. NotAfter: end,
  200. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
  201. BasicConstraintsValid: true,
  202. IsCA: true,
  203. }
  204. key, err := rsa.GenerateKey(rand.Reader, 2048)
  205. if err != nil {
  206. return nil, fmt.Errorf(errGeneratePrivateKey, err)
  207. }
  208. certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
  209. if err != nil {
  210. return nil, fmt.Errorf("failed to create certificate: %w", err)
  211. }
  212. cert, err := x509.ParseCertificate(certDER)
  213. if err != nil {
  214. return nil, fmt.Errorf("failed to parse certificate: %w", err)
  215. }
  216. certPEM := pem.EncodeToMemory(&pem.Block{
  217. Type: "CERTIFICATE",
  218. Bytes: certDER,
  219. })
  220. keyPEM := pem.EncodeToMemory(&pem.Block{
  221. Type: "RSA PRIVATE KEY",
  222. Bytes: x509.MarshalPKCS1PrivateKey(key),
  223. })
  224. return &KeyPairArtifacts{
  225. Cert: cert,
  226. Key: key,
  227. CertPEM: certPEM,
  228. KeyPEM: keyPEM,
  229. }, nil
  230. }
  231. // createProviderServerCert generates a server certificate for the provider.
  232. func (r *ProviderCertReconciler) createProviderServerCert(
  233. caArtifacts *KeyPairArtifacts,
  234. config *ProviderCertConfig,
  235. begin, end time.Time,
  236. ) ([]byte, []byte, error) {
  237. dnsNames := r.getProviderDNSNames(config)
  238. // Create certificate template
  239. template := &x509.Certificate{
  240. SerialNumber: big.NewInt(time.Now().UnixNano()),
  241. Subject: pkix.Name{
  242. CommonName: "external-secrets-provider",
  243. Organization: []string{r.CAOrganization},
  244. },
  245. DNSNames: dnsNames,
  246. NotBefore: begin,
  247. NotAfter: end,
  248. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  249. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  250. }
  251. // Generate private key
  252. key, err := rsa.GenerateKey(rand.Reader, 2048)
  253. if err != nil {
  254. return nil, nil, fmt.Errorf(errGeneratePrivateKey, err)
  255. }
  256. // Create certificate
  257. certDER, err := x509.CreateCertificate(rand.Reader, template, caArtifacts.Cert, &key.PublicKey, caArtifacts.Key)
  258. if err != nil {
  259. return nil, nil, fmt.Errorf("failed to create certificate: %w", err)
  260. }
  261. // Encode certificate
  262. certPEM := pem.EncodeToMemory(&pem.Block{
  263. Type: "CERTIFICATE",
  264. Bytes: certDER,
  265. })
  266. // Encode private key
  267. keyPEM := pem.EncodeToMemory(&pem.Block{
  268. Type: "RSA PRIVATE KEY",
  269. Bytes: x509.MarshalPKCS1PrivateKey(key),
  270. })
  271. return certPEM, keyPEM, nil
  272. }
  273. // createProviderClientCert generates a client certificate for the ESO controller.
  274. func (r *ProviderCertReconciler) createProviderClientCert(
  275. caArtifacts *KeyPairArtifacts,
  276. begin, end time.Time,
  277. ) ([]byte, []byte, error) {
  278. // Create certificate template
  279. template := &x509.Certificate{
  280. SerialNumber: big.NewInt(time.Now().UnixNano()),
  281. Subject: pkix.Name{
  282. CommonName: "external-secrets-controller",
  283. Organization: []string{r.CAOrganization},
  284. },
  285. NotBefore: begin,
  286. NotAfter: end,
  287. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  288. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
  289. }
  290. // Generate private key
  291. key, err := rsa.GenerateKey(rand.Reader, 2048)
  292. if err != nil {
  293. return nil, nil, fmt.Errorf(errGeneratePrivateKey, err)
  294. }
  295. // Create certificate
  296. certDER, err := x509.CreateCertificate(rand.Reader, template, caArtifacts.Cert, &key.PublicKey, caArtifacts.Key)
  297. if err != nil {
  298. return nil, nil, fmt.Errorf("failed to create certificate: %w", err)
  299. }
  300. // Encode certificate
  301. certPEM := pem.EncodeToMemory(&pem.Block{
  302. Type: "CERTIFICATE",
  303. Bytes: certDER,
  304. })
  305. // Encode private key
  306. keyPEM := pem.EncodeToMemory(&pem.Block{
  307. Type: "RSA PRIVATE KEY",
  308. Bytes: x509.MarshalPKCS1PrivateKey(key),
  309. })
  310. return certPEM, keyPEM, nil
  311. }
  312. // getProviderDNSNames returns the DNS names for the provider service.
  313. func (r *ProviderCertReconciler) getProviderDNSNames(config *ProviderCertConfig) []string {
  314. dnsNames := make([]string, 0, len(config.ServiceNames)*4)
  315. for _, serviceName := range config.ServiceNames {
  316. dnsNames = append(dnsNames,
  317. serviceName,
  318. fmt.Sprintf("%s.%s", serviceName, config.Namespace),
  319. fmt.Sprintf("%s.%s.svc", serviceName, config.Namespace),
  320. fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, config.Namespace),
  321. )
  322. }
  323. return dnsNames
  324. }
  325. // validCACert validates a CA certificate.
  326. func (r *ProviderCertReconciler) validCACert(caCert, caKey []byte) bool {
  327. if len(caCert) == 0 || len(caKey) == 0 {
  328. return false
  329. }
  330. // Parse CA certificate
  331. caDer, _ := pem.Decode(caCert)
  332. if caDer == nil {
  333. return false
  334. }
  335. caCertParsed, err := x509.ParseCertificate(caDer.Bytes)
  336. if err != nil {
  337. return false
  338. }
  339. // Check if CA is still valid with lookahead
  340. if time.Now().After(lookaheadTime()) && lookaheadTime().After(caCertParsed.NotAfter) {
  341. return false
  342. }
  343. return true
  344. }
  345. // validProviderCert validates a provider server certificate.
  346. func (r *ProviderCertReconciler) validProviderCert(caCert, cert, key []byte, dnsNames []string) bool {
  347. if len(caCert) == 0 || len(cert) == 0 || len(key) == 0 {
  348. return false
  349. }
  350. // Parse CA certificate
  351. pool := x509.NewCertPool()
  352. caDer, _ := pem.Decode(caCert)
  353. if caDer == nil {
  354. return false
  355. }
  356. caCertParsed, err := x509.ParseCertificate(caDer.Bytes)
  357. if err != nil {
  358. return false
  359. }
  360. pool.AddCert(caCertParsed)
  361. // Parse server certificate
  362. certDer, _ := pem.Decode(cert)
  363. if certDer == nil {
  364. return false
  365. }
  366. certParsed, err := x509.ParseCertificate(certDer.Bytes)
  367. if err != nil {
  368. return false
  369. }
  370. // Verify certificate is signed by CA
  371. opts := x509.VerifyOptions{
  372. Roots: pool,
  373. CurrentTime: lookaheadTime(),
  374. KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  375. }
  376. if _, err := certParsed.Verify(opts); err != nil {
  377. return false
  378. }
  379. // Check DNS names are present
  380. for _, dnsName := range dnsNames {
  381. if !slices.Contains(certParsed.DNSNames, dnsName) {
  382. return false
  383. }
  384. }
  385. return true
  386. }
  387. // validProviderClientCert validates a provider client certificate.
  388. func (r *ProviderCertReconciler) validProviderClientCert(caCert, cert, key []byte) bool {
  389. if len(caCert) == 0 || len(cert) == 0 || len(key) == 0 {
  390. return false
  391. }
  392. // Parse CA certificate
  393. pool := x509.NewCertPool()
  394. caDer, _ := pem.Decode(caCert)
  395. if caDer == nil {
  396. return false
  397. }
  398. caCertParsed, err := x509.ParseCertificate(caDer.Bytes)
  399. if err != nil {
  400. return false
  401. }
  402. pool.AddCert(caCertParsed)
  403. // Parse client certificate
  404. certDer, _ := pem.Decode(cert)
  405. if certDer == nil {
  406. return false
  407. }
  408. certParsed, err := x509.ParseCertificate(certDer.Bytes)
  409. if err != nil {
  410. return false
  411. }
  412. // Verify certificate is signed by CA
  413. opts := x509.VerifyOptions{
  414. Roots: pool,
  415. CurrentTime: lookaheadTime(),
  416. KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
  417. }
  418. if _, err := certParsed.Verify(opts); err != nil {
  419. return false
  420. }
  421. return true
  422. }
  423. // buildArtifactsFromSecret builds KeyPairArtifacts from a secret.
  424. func buildArtifactsFromSecret(secret *corev1.Secret) (*KeyPairArtifacts, error) {
  425. caCertPEM := secret.Data[caCertName]
  426. caKeyPEM := secret.Data[caKeyName]
  427. caDer, _ := pem.Decode(caCertPEM)
  428. if caDer == nil {
  429. return nil, fmt.Errorf("failed to decode CA certificate")
  430. }
  431. caCert, err := x509.ParseCertificate(caDer.Bytes)
  432. if err != nil {
  433. return nil, fmt.Errorf("failed to parse CA certificate: %w", err)
  434. }
  435. keyDer, _ := pem.Decode(caKeyPEM)
  436. if keyDer == nil {
  437. return nil, fmt.Errorf("failed to decode CA key")
  438. }
  439. caKey, err := x509.ParsePKCS1PrivateKey(keyDer.Bytes)
  440. if err != nil {
  441. return nil, fmt.Errorf("failed to parse CA key: %w", err)
  442. }
  443. return &KeyPairArtifacts{
  444. Cert: caCert,
  445. Key: caKey,
  446. CertPEM: caCertPEM,
  447. KeyPEM: caKeyPEM,
  448. }, nil
  449. }
  450. // lookaheadTime returns the current time plus a lookahead duration
  451. // to ensure certificates are refreshed before expiration.
  452. func lookaheadTime() time.Time {
  453. return time.Now().Add(365 * 24 * time.Hour) // 1 year lookahead
  454. }