Skip to content

Commit f648c78

Browse files
Merge pull request #156 from bryan-cox/HOSTEDCP-1994
HOSTEDCP-2035: Use Client Cert Auth for ARO HCP deployments
2 parents a6bc591 + ba58106 commit f648c78

File tree

3 files changed

+96
-7
lines changed

3 files changed

+96
-7
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
1111
github.com/Azure/go-autorest/autorest v0.11.27
1212
github.com/aws/aws-sdk-go v1.37.8
13+
github.com/fsnotify/fsnotify v1.7.0
1314
github.com/google/uuid v1.6.0
1415
github.com/gophercloud/gophercloud/v2 v2.1.1
1516
github.com/gophercloud/utils/v2 v2.0.0-20241008104625-7cbb8fd76bb7
@@ -52,7 +53,6 @@ require (
5253
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
5354
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
5455
github.com/felixge/httpsnoop v1.0.4 // indirect
55-
github.com/fsnotify/fsnotify v1.7.0 // indirect
5656
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
5757
github.com/go-logr/logr v1.4.2 // indirect
5858
github.com/go-logr/stdr v1.2.2 // indirect

pkg/cloudprovider/azure.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/jongio/azidext/go/azidext"
2121
v1 "github.com/openshift/api/cloudnetwork/v1"
2222
configv1 "github.com/openshift/api/config/v1"
23+
"github.com/openshift/cloud-network-config-controller/pkg/filewatcher"
2324
corev1 "k8s.io/api/core/v1"
2425
"k8s.io/klog/v2"
2526
utilnet "k8s.io/utils/net"
@@ -586,17 +587,37 @@ func (a *Azure) getAuthorizer(env azureapi.Environment, cfg *azureCredentialsCon
586587
err error
587588
)
588589

589-
// MSI Override for ARO HCP
590-
msi := os.Getenv("AZURE_MSI_AUTHENTICATION")
591-
if msi == "true" {
592-
options := azidentity.ManagedIdentityCredentialOptions{
590+
// Managed Identity Override for ARO HCP
591+
managedIdentityClientID := os.Getenv("ARO_HCP_MI_CLIENT_ID")
592+
if managedIdentityClientID != "" {
593+
klog.Info("Using client certification Azure authentication for ARO HCP")
594+
options := &azidentity.ClientCertificateCredentialOptions{
593595
ClientOptions: azcore.ClientOptions{
594596
Cloud: cloudConfig,
595597
},
598+
SendCertificateChain: true,
596599
}
597600

598-
var err error
599-
cred, err = azidentity.NewManagedIdentityCredential(&options)
601+
tenantID := os.Getenv("ARO_HCP_TENANT_ID")
602+
certPath := os.Getenv("ARO_HCP_CLIENT_CERTIFICATE_PATH")
603+
604+
certData, err := os.ReadFile(certPath)
605+
if err != nil {
606+
return nil, fmt.Errorf(`failed to read certificate file "%s": %v`, certPath, err)
607+
}
608+
609+
certs, key, err := azidentity.ParseCertificates(certData, []byte{})
610+
if err != nil {
611+
return nil, fmt.Errorf(`failed to parse certificate data "%s": %v`, certPath, err)
612+
}
613+
614+
// Watch the certificate for changes; if the certificate changes, the pod will be restarted
615+
err = filewatcher.WatchFileForChanges(certPath)
616+
if err != nil {
617+
return nil, err
618+
}
619+
620+
cred, err = azidentity.NewClientCertificateCredential(tenantID, managedIdentityClientID, certs, key, options)
600621
if err != nil {
601622
return nil, err
602623
}

pkg/filewatcher/filewatcher.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package filewatcher
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"sync"
7+
8+
"github.com/fsnotify/fsnotify"
9+
"k8s.io/klog/v2"
10+
)
11+
12+
var watchCertificateFileOnce sync.Once
13+
14+
// WatchFileForChanges watches the file, fileToWatch, for changes. If the file contents have changed, the pod this
15+
// function is running on will be restarted.
16+
func WatchFileForChanges(fileToWatch string) error {
17+
var err error
18+
19+
// This starts only one occurrence of the file watcher, which watches the file, fileToWatch.
20+
watchCertificateFileOnce.Do(func() {
21+
klog.Infof("Starting the file change watcher on file, %s", fileToWatch)
22+
23+
// Update the file path to watch in case this is a symlink
24+
fileToWatch, err = filepath.EvalSymlinks(fileToWatch)
25+
if err != nil {
26+
return
27+
}
28+
klog.Infof("Watching file, %s", fileToWatch)
29+
30+
// Start the file watcher to monitor file changes
31+
go func() {
32+
err := checkForFileChanges(fileToWatch)
33+
klog.Errorf("Error checking for file changes: %v", err)
34+
}()
35+
})
36+
return err
37+
}
38+
39+
// checkForFileChanges starts a new file watcher. If the file is changed, the pod running this function will exit.
40+
func checkForFileChanges(path string) error {
41+
watcher, err := fsnotify.NewWatcher()
42+
if err != nil {
43+
return err
44+
}
45+
46+
go func() {
47+
for {
48+
select {
49+
case event, ok := <-watcher.Events:
50+
if ok && (event.Has(fsnotify.Write) || event.Has(fsnotify.Chmod) || event.Has(fsnotify.Remove)) {
51+
klog.Infof("file, %s, was modified, exiting...", event.Name)
52+
os.Exit(0)
53+
}
54+
case err, ok := <-watcher.Errors:
55+
if ok {
56+
klog.Errorf("file watcher error: %v", err)
57+
}
58+
}
59+
}
60+
}()
61+
62+
err = watcher.Add(path)
63+
if err != nil {
64+
return err
65+
}
66+
67+
return nil
68+
}

0 commit comments

Comments
 (0)