6
6
"fmt"
7
7
"net/http"
8
8
"os"
9
+ "path/filepath"
9
10
"strings"
10
11
11
12
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
@@ -21,6 +22,9 @@ import (
21
22
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
22
23
autorestazure "github.com/Azure/go-autorest/autorest/azure"
23
24
"github.com/Azure/go-autorest/autorest/to"
25
+ "github.com/fsnotify/fsnotify"
26
+ "k8s.io/klog/v2"
27
+ "k8s.io/kubernetes/pkg/util/interrupt"
24
28
)
25
29
26
30
const (
@@ -105,13 +109,44 @@ func (c *Client) getCreds() (azcore.TokenCredential, error) {
105
109
// Managed Identity Override for ARO HCP
106
110
managedIdentityClientID := os .Getenv ("ARO_HCP_MI_CLIENT_ID" )
107
111
if managedIdentityClientID != "" {
108
- options := azidentity.ManagedIdentityCredentialOptions {
112
+ klog .V (2 ).Info ("Using client certification Azure authentication for ARO HCP" )
113
+ options := & azidentity.ClientCertificateCredentialOptions {
109
114
ClientOptions : azcore.ClientOptions {
110
115
Cloud : c .clientOpts .Cloud ,
111
116
},
112
- ID : azidentity . ClientID ( managedIdentityClientID ) ,
117
+ SendCertificateChain : true ,
113
118
}
114
- creds , err = azidentity .NewManagedIdentityCredential (& options )
119
+
120
+ tenantID := os .Getenv ("ARO_HCP_TENANT_ID" )
121
+ certPath := os .Getenv ("ARO_HCP_CLIENT_CERTIFICATE_PATH" )
122
+
123
+ certData , err := os .ReadFile (certPath )
124
+ if err != nil {
125
+ return nil , fmt .Errorf (`failed to read certificate file "%s": %v` , certPath , err )
126
+ }
127
+
128
+ certs , key , err := azidentity .ParseCertificates (certData , []byte {})
129
+ if err != nil {
130
+ return nil , fmt .Errorf (`failed to parse certificate data "%s": %v` , certPath , err )
131
+ }
132
+
133
+ // Set up a watch on our config file; if it changes, we should exit -
134
+ // (we don't have the ability to dynamically reload config changes).
135
+ stopCh := make (chan struct {})
136
+ err = interrupt .New (func (s os.Signal ) {
137
+ _ , _ = fmt .Fprintf (os .Stderr , "interrupt: Gracefully shutting down ...\n " )
138
+ close (stopCh )
139
+ }).Run (func () error {
140
+ if err := WatchForChanges (certPath , stopCh ); err != nil {
141
+ return err
142
+ }
143
+ return nil
144
+ })
145
+ if err != nil {
146
+ return nil , err
147
+ }
148
+
149
+ creds , err = azidentity .NewClientCertificateCredential (tenantID , managedIdentityClientID , certs , key , options )
115
150
if err != nil {
116
151
return nil , err
117
152
}
@@ -904,3 +939,59 @@ func (client *BlobClient) DeleteStorageContainer(ctx context.Context, containerN
904
939
_ , err := client .client .DeleteContainer (ctx , containerName , & azblob.DeleteContainerOptions {})
905
940
return err
906
941
}
942
+
943
+ // WatchForChanges closes stopCh if the configuration file changed.
944
+ func WatchForChanges (configPath string , stopCh chan struct {}) error {
945
+ configPath , err := filepath .Abs (configPath )
946
+ if err != nil {
947
+ return err
948
+ }
949
+ watcher , err := fsnotify .NewWatcher ()
950
+ if err != nil {
951
+ return err
952
+ }
953
+ // Watch all symlinks for changes
954
+ p := configPath
955
+ maxDepth := 100
956
+ for depth := 0 ; depth < maxDepth ; depth ++ {
957
+ if err := watcher .Add (p ); err != nil {
958
+ return err
959
+ }
960
+ klog .V (2 ).Infof ("Watching config file %s for changes" , p )
961
+ stat , err := os .Lstat (p )
962
+ if err != nil {
963
+ return err
964
+ }
965
+ // configmaps are usually symlinks
966
+ if stat .Mode ()& os .ModeSymlink > 0 {
967
+ p , err = filepath .EvalSymlinks (p )
968
+ if err != nil {
969
+ return err
970
+ }
971
+ } else {
972
+ break
973
+ }
974
+ }
975
+ go func () {
976
+ for {
977
+ select {
978
+ case <- stopCh :
979
+ case event , ok := <- watcher .Events :
980
+ if ! ok {
981
+ klog .Errorf ("failed to watch config file %s" , p )
982
+ return
983
+ }
984
+ klog .V (2 ).Infof ("Configuration file %s changed, exiting..." , event .Name )
985
+ close (stopCh )
986
+ return
987
+ case err , ok := <- watcher .Errors :
988
+ if ! ok {
989
+ klog .Errorf ("failed to watch config file %s" , p )
990
+ return
991
+ }
992
+ klog .Errorf ("fsnotify error: %v" , err )
993
+ }
994
+ }
995
+ }()
996
+ return nil
997
+ }
0 commit comments