certs.go 15 KB

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