-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
159 lines (134 loc) · 5.24 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main
import (
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/data/aztables"
"github.com/google/go-github/v62/github"
"log"
"os"
apis "secretRotator/apis"
"secretRotator/helpers"
graphhelper "secretRotator/helpers"
)
func main() {
log.Println("Starting Secret Rotator Orhcestrator")
helpers.GetEnvironmentVariablesFromKeyVault()
tenantId := helpers.SecretsMap["TENANT-ID"]
graphHelper, azTablesClient, githubClient := initializeClients()
entities := graphhelper.GetEntitiesFromStorage(azTablesClient)
for _, entity := range entities {
processEntity(entity, graphHelper, *azTablesClient, githubClient, tenantId)
}
}
func initializeClients() (graphHelper *graphhelper.GraphHelper, azTablesClient *aztables.Client, githubClient *github.Client) {
// Initialize Graph Client
graphHelper = graphhelper.NewGraphHelper()
if err := graphHelper.InitializeGraphForAppAuth(); err != nil {
log.Fatal("Error initializing Graph Client")
}
storageAccountName := helpers.SecretsMap["AZURE-STORAGE-ACCOUNT"]
tableName := helpers.SecretsMap["AZURE-TABLE-NAME"]
serviceURL := fmt.Sprintf("https://%s.table.core.windows.net/%s", storageAccountName, tableName)
azTablesClient = helpers.AzTablesClient(serviceURL)
// Check if GitHub private key exists, if not don't try to innitialize GitHub client
if _, err := os.Stat("azuresecretrotator.private-key.pem"); err == nil {
githubClient = apis.GithubClient()
log.Println("GitHub client initialized")
return graphHelper, azTablesClient, githubClient
} else {
return graphHelper, azTablesClient, nil
}
}
func processEntity(entity graphhelper.Entity, graphHelper *graphhelper.GraphHelper, azTablesClient aztables.Client, githubClient *github.Client, tenantId string) {
// Handle entity...
var mySecretName string
mySecretName = entity.SecretName
if entity.KeyVaultName == "" {
log.Printf("KeyVault is mandatory field")
log.Printf("KeyVaultName is empty for entity: %s", entity.AppRegistrationName)
return
}
if entity.PartitionKey == "0" {
return
}
if entity.Reprocess == true {
log.Println("Reprocessing entity...")
vaultUri := fmt.Sprintf("https://%s.vault.azure.net/", entity.KeyVaultName)
keyVaultClient, err := helpers.KeyVaultClient(vaultUri)
if err != nil {
log.Printf("error creating KeyVault client: %v", err)
}
secretValue, err := helpers.GetKeyVaultSecret(mySecretName, entity.KeyVaultName, keyVaultClient)
if githubClient != nil {
ok := apis.CreateOrUpdateGithubSecret(githubClient, entity.GithubRepository, entity.AppRegistrationObjectId, secretValue, tenantId, entity.SubscriptionID)
if ok == true {
reprocess := false
helpers.MarkEntityForReprocessing(&azTablesClient, entity, reprocess)
}
}
}
if entity.Reprocess == false {
secretValue, err := getAndUpdateAppRegistrationAndKeyVault(entity, graphHelper, azTablesClient, mySecretName)
if err != nil {
log.Printf("error getting and updating app registration and key vault: %v", err)
}
// Make Github call
appId, err := graphHelper.GetApplicationId(entity.AppRegistrationObjectId)
if err != nil {
log.Printf("error getting application ID: %v", err)
}
if githubClient != nil {
ok := apis.CreateOrUpdateGithubSecret(githubClient, entity.GithubRepository, appId, secretValue, tenantId, entity.SubscriptionID)
if ok != true {
reprocess := true
helpers.MarkEntityForReprocessing(&azTablesClient, entity, reprocess)
}
}
}
}
func getAndUpdateAppRegistrationAndKeyVault(entity graphhelper.Entity, graphHelper *graphhelper.GraphHelper, azTablesClient aztables.Client, mySecretName string) (secretValue string, err error) {
objectId := entity.AppRegistrationObjectId
keyVaultName := entity.KeyVaultName
passwordCredentials, credentialCount, err := graphHelper.GetApplicationById(objectId, keyVaultName)
if err != nil {
log.Printf("error retrieving application by ID: %v", err)
return "", err
}
if credentialCount == 0 {
// More functionality to create the first secret could be added later on.
log.Printf("no credentials found for object ID: %s", objectId)
return "", err
}
switch {
case credentialCount < 2:
secretValue, err = graphHelper.GetCredentialExpiration(passwordCredentials, objectId, keyVaultName, mySecretName)
if err != nil {
log.Printf("error getting credential expiration: %v", err)
return "", err
}
if secretValue != "" {
ok := helpers.UploadToKeyVault(secretValue, keyVaultName, mySecretName)
if !ok {
// Cleanup actions after failing to upload to KeyVault.
err = graphHelper.DeleteSecretKeyVaultFail(passwordCredentials, objectId)
if err != nil {
log.Printf("failed to clean up after upload to KeyVault failed: %v", err)
}
log.Printf("failed to upload secret to KeyVault for object ID: %s", objectId)
return "", err
}
if entity.NotificationEmail != "" {
// apis.SendMail(entity.NotificationEmail, entity.AppRegistrationName, keyVaultName, mySecretName)
log.Println("Send email, replace with sendgrid in Azure")
}
}
case credentialCount >= 2:
err = graphHelper.GetExpirationAndDelete(passwordCredentials, objectId)
if err != nil {
log.Printf("error managing multiple credential expirations: %v", err)
return "", err
}
default:
// Optional: handle other cases if necessary.
}
return secretValue, nil
}