crds_controller.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package crds
  13. import (
  14. "bytes"
  15. "context"
  16. "crypto/rand"
  17. "crypto/rsa"
  18. "crypto/tls"
  19. "crypto/x509"
  20. "crypto/x509/pkix"
  21. "encoding/pem"
  22. "errors"
  23. "fmt"
  24. "math/big"
  25. "net/http"
  26. "os"
  27. "path/filepath"
  28. "slices"
  29. "sync"
  30. "time"
  31. "github.com/go-logr/logr"
  32. corev1 "k8s.io/api/core/v1"
  33. apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  34. "k8s.io/apimachinery/pkg/api/equality"
  35. "k8s.io/apimachinery/pkg/runtime"
  36. "k8s.io/apimachinery/pkg/types"
  37. "k8s.io/client-go/tools/record"
  38. ctrl "sigs.k8s.io/controller-runtime"
  39. "sigs.k8s.io/controller-runtime/pkg/client"
  40. "sigs.k8s.io/controller-runtime/pkg/controller"
  41. )
  42. const (
  43. certName = "tls.crt"
  44. keyName = "tls.key"
  45. caCertName = "ca.crt"
  46. caKeyName = "ca.key"
  47. certValidityDuration = 10 * 365 * 24 * time.Hour
  48. LookaheadInterval = 90 * 24 * time.Hour
  49. errResNotReady = "resource not ready: %s"
  50. errSubsetsNotReady = "subsets not ready"
  51. errAddressesNotReady = "addresses not ready"
  52. )
  53. type Reconciler struct {
  54. client.Client
  55. Log logr.Logger
  56. Scheme *runtime.Scheme
  57. recorder record.EventRecorder
  58. SvcName string
  59. SvcNamespace string
  60. SecretName string
  61. SecretNamespace string
  62. CrdResources []string
  63. dnsName string
  64. CAName string
  65. CAChainName string
  66. CAOrganization string
  67. RequeueInterval time.Duration
  68. // the controller is ready when all crds are injected
  69. // and the controller is elected as leader
  70. leaderChan <-chan struct{}
  71. leaderElected bool
  72. readyStatusMapMu *sync.Mutex
  73. readyStatusMap map[string]bool
  74. }
  75. type Opts struct {
  76. SvcName string
  77. SvcNamespace string
  78. SecretName string
  79. SecretNamespace string
  80. Resources []string
  81. }
  82. func New(k8sClient client.Client, scheme *runtime.Scheme, leaderChan <-chan struct{}, logger logr.Logger,
  83. interval time.Duration, opts Opts) *Reconciler {
  84. return &Reconciler{
  85. Client: k8sClient,
  86. Log: logger,
  87. Scheme: scheme,
  88. SvcName: opts.SvcName,
  89. SvcNamespace: opts.SvcNamespace,
  90. SecretName: opts.SecretName,
  91. SecretNamespace: opts.SecretNamespace,
  92. RequeueInterval: interval,
  93. CrdResources: opts.Resources,
  94. CAName: "external-secrets",
  95. CAOrganization: "external-secrets",
  96. leaderChan: leaderChan,
  97. readyStatusMapMu: &sync.Mutex{},
  98. readyStatusMap: map[string]bool{},
  99. }
  100. }
  101. type CertInfo struct {
  102. CertDir string
  103. CertName string
  104. KeyName string
  105. CAName string
  106. }
  107. func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  108. log := r.Log.WithValues("CustomResourceDefinition", req.NamespacedName)
  109. if slices.Contains(r.CrdResources, req.NamespacedName.Name) {
  110. err := r.updateCRD(logr.NewContext(ctx, log), req)
  111. if err != nil {
  112. log.Error(err, "failed to inject conversion webhook")
  113. r.readyStatusMapMu.Lock()
  114. r.readyStatusMap[req.NamespacedName.Name] = false
  115. r.readyStatusMapMu.Unlock()
  116. return ctrl.Result{}, err
  117. }
  118. r.readyStatusMapMu.Lock()
  119. r.readyStatusMap[req.NamespacedName.Name] = true
  120. r.readyStatusMapMu.Unlock()
  121. }
  122. return ctrl.Result{RequeueAfter: r.RequeueInterval}, nil
  123. }
  124. // ReadyCheck reviews if all webhook configs have been injected into the CRDs
  125. // and if the referenced webhook service is ready.
  126. func (r *Reconciler) ReadyCheck(_ *http.Request) error {
  127. // skip readiness check if we're not leader
  128. // as we depend on caches and being able to reconcile Webhooks
  129. if !r.leaderElected {
  130. select {
  131. case <-r.leaderChan:
  132. r.leaderElected = true
  133. default:
  134. return nil
  135. }
  136. }
  137. if err := r.checkCRDs(); err != nil {
  138. return err
  139. }
  140. return r.checkEndpoints()
  141. }
  142. func (r *Reconciler) checkCRDs() error {
  143. for _, res := range r.CrdResources {
  144. r.readyStatusMapMu.Lock()
  145. rdy := r.readyStatusMap[res]
  146. r.readyStatusMapMu.Unlock()
  147. if !rdy {
  148. return fmt.Errorf(errResNotReady, res)
  149. }
  150. }
  151. return nil
  152. }
  153. func (r *Reconciler) checkEndpoints() error {
  154. var eps corev1.Endpoints
  155. err := r.Get(context.TODO(), types.NamespacedName{
  156. Name: r.SvcName,
  157. Namespace: r.SvcNamespace,
  158. }, &eps)
  159. if err != nil {
  160. return err
  161. }
  162. if len(eps.Subsets) == 0 {
  163. return errors.New(errSubsetsNotReady)
  164. }
  165. if len(eps.Subsets[0].Addresses) == 0 {
  166. return errors.New(errAddressesNotReady)
  167. }
  168. return nil
  169. }
  170. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager, opts controller.Options) error {
  171. r.recorder = mgr.GetEventRecorderFor("custom-resource-definition")
  172. return ctrl.NewControllerManagedBy(mgr).
  173. WithOptions(opts).
  174. For(&apiext.CustomResourceDefinition{}).
  175. Complete(r)
  176. }
  177. func (r *Reconciler) updateCRD(ctx context.Context, req ctrl.Request) error {
  178. log := logr.FromContextOrDiscard(ctx)
  179. secret := corev1.Secret{}
  180. secretName := types.NamespacedName{
  181. Name: r.SecretName,
  182. Namespace: r.SecretNamespace,
  183. }
  184. err := r.Get(context.Background(), secretName, &secret)
  185. if err != nil {
  186. return err
  187. }
  188. var updatedResource apiext.CustomResourceDefinition
  189. if err := r.Get(ctx, req.NamespacedName, &updatedResource); err != nil {
  190. return err
  191. }
  192. before := updatedResource.DeepCopyObject()
  193. svc := types.NamespacedName{
  194. Name: r.SvcName,
  195. Namespace: r.SvcNamespace,
  196. }
  197. if err := injectService(&updatedResource, svc); err != nil {
  198. return err
  199. }
  200. r.dnsName = fmt.Sprintf("%v.%v.svc", r.SvcName, r.SvcNamespace)
  201. need, err := r.refreshCertIfNeeded(&secret)
  202. if err != nil {
  203. return err
  204. }
  205. if need {
  206. artifacts, err := buildArtifactsFromSecret(&secret)
  207. if err != nil {
  208. return err
  209. }
  210. if err := injectCert(&updatedResource, artifacts.CertPEM); err != nil {
  211. return err
  212. }
  213. }
  214. if !equality.Semantic.DeepEqual(before, &updatedResource) {
  215. if err := r.Update(ctx, &updatedResource); err != nil {
  216. return err
  217. }
  218. log.Info("updated crd")
  219. return nil
  220. }
  221. log.V(1).Info("crd is unchanged")
  222. return nil
  223. }
  224. func injectService(crd *apiext.CustomResourceDefinition, svc types.NamespacedName) error {
  225. if crd.Spec.Conversion != nil && crd.Spec.Conversion.Strategy == apiext.NoneConverter {
  226. return nil
  227. }
  228. if crd.Spec.Conversion == nil ||
  229. crd.Spec.Conversion.Webhook == nil ||
  230. crd.Spec.Conversion.Webhook.ClientConfig == nil ||
  231. crd.Spec.Conversion.Webhook.ClientConfig.Service == nil {
  232. return errors.New("unexpected crd conversion webhook config")
  233. }
  234. crd.Spec.Conversion.Webhook.ClientConfig.Service.Namespace = svc.Namespace
  235. crd.Spec.Conversion.Webhook.ClientConfig.Service.Name = svc.Name
  236. return nil
  237. }
  238. func injectCert(crd *apiext.CustomResourceDefinition, certPem []byte) error {
  239. if crd.Spec.Conversion != nil && crd.Spec.Conversion.Strategy == apiext.NoneConverter {
  240. return nil
  241. }
  242. if crd.Spec.Conversion == nil ||
  243. crd.Spec.Conversion.Webhook == nil ||
  244. crd.Spec.Conversion.Webhook.ClientConfig == nil {
  245. return errors.New("unexpected crd conversion webhook config")
  246. }
  247. crd.Spec.Conversion.Webhook.ClientConfig.CABundle = certPem
  248. return nil
  249. }
  250. type KeyPairArtifacts struct {
  251. Cert *x509.Certificate
  252. Key *rsa.PrivateKey
  253. CertPEM []byte
  254. KeyPEM []byte
  255. }
  256. func populateSecret(cert, key []byte, caArtifacts *KeyPairArtifacts, secret *corev1.Secret) {
  257. if secret.Data == nil {
  258. secret.Data = make(map[string][]byte)
  259. }
  260. secret.Data[caCertName] = caArtifacts.CertPEM
  261. secret.Data[caKeyName] = caArtifacts.KeyPEM
  262. secret.Data[certName] = cert
  263. secret.Data[keyName] = key
  264. }
  265. func ValidCert(caCert, cert, key []byte, dnsName string, at time.Time) (bool, error) {
  266. if len(caCert) == 0 || len(cert) == 0 || len(key) == 0 {
  267. return false, errors.New("empty cert")
  268. }
  269. pool := x509.NewCertPool()
  270. caDer, _ := pem.Decode(caCert)
  271. if caDer == nil {
  272. return false, errors.New("bad CA cert")
  273. }
  274. cac, err := x509.ParseCertificate(caDer.Bytes)
  275. if err != nil {
  276. return false, err
  277. }
  278. pool.AddCert(cac)
  279. _, err = tls.X509KeyPair(cert, key)
  280. if err != nil {
  281. return false, err
  282. }
  283. b, rest := pem.Decode(cert)
  284. if b == nil {
  285. return false, err
  286. }
  287. if len(rest) > 0 {
  288. intermediate, _ := pem.Decode(rest)
  289. inter, err := x509.ParseCertificate(intermediate.Bytes)
  290. if err != nil {
  291. return false, err
  292. }
  293. pool.AddCert(inter)
  294. }
  295. crt, err := x509.ParseCertificate(b.Bytes)
  296. if err != nil {
  297. return false, err
  298. }
  299. _, err = crt.Verify(x509.VerifyOptions{
  300. DNSName: dnsName,
  301. Roots: pool,
  302. CurrentTime: at,
  303. })
  304. if err != nil {
  305. return false, err
  306. }
  307. return true, nil
  308. }
  309. func lookaheadTime() time.Time {
  310. return time.Now().Add(LookaheadInterval)
  311. }
  312. func (r *Reconciler) validServerCert(caCert, cert, key []byte) bool {
  313. valid, err := ValidCert(caCert, cert, key, r.dnsName, lookaheadTime())
  314. if err != nil {
  315. return false
  316. }
  317. return valid
  318. }
  319. func (r *Reconciler) validCACert(cert, key []byte) bool {
  320. valid, err := ValidCert(cert, cert, key, r.CAName, lookaheadTime())
  321. if err != nil {
  322. return false
  323. }
  324. return valid
  325. }
  326. func (r *Reconciler) refreshCertIfNeeded(secret *corev1.Secret) (bool, error) {
  327. if secret.Data == nil || !r.validCACert(secret.Data[caCertName], secret.Data[caKeyName]) {
  328. if err := r.refreshCerts(true, secret); err != nil {
  329. return false, err
  330. }
  331. return true, nil
  332. }
  333. if !r.validServerCert(secret.Data[caCertName], secret.Data[certName], secret.Data[keyName]) {
  334. if err := r.refreshCerts(false, secret); err != nil {
  335. return false, err
  336. }
  337. return true, nil
  338. }
  339. return true, nil
  340. }
  341. func (r *Reconciler) refreshCerts(refreshCA bool, secret *corev1.Secret) error {
  342. var caArtifacts *KeyPairArtifacts
  343. now := time.Now()
  344. begin := now.Add(-1 * time.Hour)
  345. end := now.Add(certValidityDuration)
  346. if refreshCA {
  347. var err error
  348. caArtifacts, err = r.CreateCACert(begin, end)
  349. if err != nil {
  350. return err
  351. }
  352. } else {
  353. var err error
  354. caArtifacts, err = buildArtifactsFromSecret(secret)
  355. if err != nil {
  356. return err
  357. }
  358. }
  359. cert, key, err := r.CreateCertPEM(caArtifacts, begin, end)
  360. if err != nil {
  361. return err
  362. }
  363. return r.writeSecret(cert, key, caArtifacts, secret)
  364. }
  365. func buildArtifactsFromSecret(secret *corev1.Secret) (*KeyPairArtifacts, error) {
  366. caPem, ok := secret.Data[caCertName]
  367. if !ok {
  368. return nil, fmt.Errorf("cert secret is not well-formed, missing %s", caCertName)
  369. }
  370. keyPem, ok := secret.Data[caKeyName]
  371. if !ok {
  372. return nil, fmt.Errorf("cert secret is not well-formed, missing %s", caKeyName)
  373. }
  374. caDer, _ := pem.Decode(caPem)
  375. if caDer == nil {
  376. return nil, errors.New("bad CA cert")
  377. }
  378. caCert, err := x509.ParseCertificate(caDer.Bytes)
  379. if err != nil {
  380. return nil, err
  381. }
  382. keyDer, _ := pem.Decode(keyPem)
  383. if keyDer == nil {
  384. return nil, err
  385. }
  386. key, err := x509.ParsePKCS1PrivateKey(keyDer.Bytes)
  387. if err != nil {
  388. return nil, err
  389. }
  390. return &KeyPairArtifacts{
  391. Cert: caCert,
  392. CertPEM: caPem,
  393. KeyPEM: keyPem,
  394. Key: key,
  395. }, nil
  396. }
  397. func (r *Reconciler) CreateCACert(begin, end time.Time) (*KeyPairArtifacts, error) {
  398. templ := &x509.Certificate{
  399. SerialNumber: big.NewInt(0),
  400. Subject: pkix.Name{
  401. CommonName: r.CAName,
  402. Organization: []string{r.CAOrganization},
  403. },
  404. DNSNames: []string{
  405. r.CAName,
  406. },
  407. NotBefore: begin,
  408. NotAfter: end,
  409. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
  410. BasicConstraintsValid: true,
  411. IsCA: true,
  412. }
  413. key, err := rsa.GenerateKey(rand.Reader, 2048)
  414. if err != nil {
  415. return nil, err
  416. }
  417. der, err := x509.CreateCertificate(rand.Reader, templ, templ, key.Public(), key)
  418. if err != nil {
  419. return nil, err
  420. }
  421. certPEM, keyPEM, err := pemEncode(der, key)
  422. if err != nil {
  423. return nil, err
  424. }
  425. cert, err := x509.ParseCertificate(der)
  426. if err != nil {
  427. return nil, err
  428. }
  429. return &KeyPairArtifacts{Cert: cert, Key: key, CertPEM: certPEM, KeyPEM: keyPEM}, nil
  430. }
  431. func (r *Reconciler) CreateCAChain(ca *KeyPairArtifacts, begin, end time.Time) (*KeyPairArtifacts, error) {
  432. templ := &x509.Certificate{
  433. SerialNumber: big.NewInt(2),
  434. Subject: pkix.Name{
  435. CommonName: r.CAChainName,
  436. Organization: []string{r.CAOrganization},
  437. },
  438. DNSNames: []string{
  439. r.CAChainName,
  440. },
  441. NotBefore: begin,
  442. NotAfter: end,
  443. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
  444. BasicConstraintsValid: true,
  445. IsCA: true,
  446. }
  447. key, err := rsa.GenerateKey(rand.Reader, 2048)
  448. if err != nil {
  449. return nil, err
  450. }
  451. der, err := x509.CreateCertificate(rand.Reader, templ, ca.Cert, key.Public(), ca.Key)
  452. if err != nil {
  453. return nil, err
  454. }
  455. certPEM, keyPEM, err := pemEncode(der, key)
  456. if err != nil {
  457. return nil, err
  458. }
  459. cert, err := x509.ParseCertificate(der)
  460. if err != nil {
  461. return nil, err
  462. }
  463. return &KeyPairArtifacts{Cert: cert, Key: key, CertPEM: certPEM, KeyPEM: keyPEM}, nil
  464. }
  465. func (r *Reconciler) CreateCertPEM(ca *KeyPairArtifacts, begin, end time.Time) ([]byte, []byte, error) {
  466. templ := &x509.Certificate{
  467. SerialNumber: big.NewInt(1),
  468. Subject: pkix.Name{
  469. CommonName: r.dnsName,
  470. },
  471. DNSNames: []string{
  472. r.dnsName,
  473. },
  474. NotBefore: begin,
  475. NotAfter: end,
  476. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  477. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  478. BasicConstraintsValid: true,
  479. }
  480. key, err := rsa.GenerateKey(rand.Reader, 2048)
  481. if err != nil {
  482. return nil, nil, err
  483. }
  484. der, err := x509.CreateCertificate(rand.Reader, templ, ca.Cert, key.Public(), ca.Key)
  485. if err != nil {
  486. return nil, nil, err
  487. }
  488. certPEM, keyPEM, err := pemEncode(der, key)
  489. if err != nil {
  490. return nil, nil, err
  491. }
  492. return certPEM, keyPEM, nil
  493. }
  494. func pemEncode(certificateDER []byte, key *rsa.PrivateKey) ([]byte, []byte, error) {
  495. certBuf := &bytes.Buffer{}
  496. if err := pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: certificateDER}); err != nil {
  497. return nil, nil, err
  498. }
  499. keyBuf := &bytes.Buffer{}
  500. if err := pem.Encode(keyBuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil {
  501. return nil, nil, err
  502. }
  503. return certBuf.Bytes(), keyBuf.Bytes(), nil
  504. }
  505. func (r *Reconciler) writeSecret(cert, key []byte, caArtifacts *KeyPairArtifacts, secret *corev1.Secret) error {
  506. populateSecret(cert, key, caArtifacts, secret)
  507. return r.Update(context.Background(), secret)
  508. }
  509. // CheckCerts verifies that certificates exist in a given fs location
  510. // and if they're valid.
  511. func CheckCerts(c CertInfo, dnsName string, at time.Time) error {
  512. certFile := filepath.Join(c.CertDir, c.CertName)
  513. _, err := os.Stat(certFile)
  514. if err != nil {
  515. return err
  516. }
  517. ca, err := os.ReadFile(filepath.Join(c.CertDir, c.CAName))
  518. if err != nil {
  519. return err
  520. }
  521. cert, err := os.ReadFile(filepath.Join(c.CertDir, c.CertName))
  522. if err != nil {
  523. return err
  524. }
  525. key, err := os.ReadFile(filepath.Join(c.CertDir, c.KeyName))
  526. if err != nil {
  527. return err
  528. }
  529. ok, err := ValidCert(ca, cert, key, dnsName, at)
  530. if err != nil {
  531. return err
  532. }
  533. if !ok {
  534. return errors.New("certificate is not valid")
  535. }
  536. return nil
  537. }