This repository has been archived by the owner on Oct 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation refreshECRToken()
- Loading branch information
Lucas Rodriguez
committed
Dec 6, 2023
1 parent
ea72aca
commit d238968
Showing
9 changed files
with
189 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { Log } from "pepr"; | ||
import { ECRPrivate, privateECRURLPattern } from "../../ecr-private"; | ||
import { ECRPublic, publicECRURLPattern } from "../../ecr-public"; | ||
import { getSecret, listNamespaces, updateSecret } from "../../lib/k8s"; | ||
import { ZarfState } from "../../zarf-types"; | ||
|
||
const zarfNamespace = "zarf"; | ||
const zarfImagePullSecret = "private-registry"; | ||
const zarfStateSecret = "zarf-state"; | ||
const zarfAgentLabel = "zarf.dev/agent"; | ||
const zarfManagedByLabel = "app.kubernetes.io/managed-by"; | ||
|
||
export async function refreshECRToken(): Promise<void> { | ||
let authToken: string = ""; | ||
const region = process.env.AWS_REGION; | ||
|
||
if (!region) { | ||
Log.error("AWS_REGION environment variable is not defined."); | ||
return; | ||
} | ||
|
||
try { | ||
const ecrURL = await getECRURL(); | ||
|
||
if (privateECRURLPattern.test(ecrURL)) { | ||
const ecrPrivate = new ECRPrivate(region); | ||
authToken = await ecrPrivate.fetchECRToken(); | ||
} | ||
|
||
if (publicECRURLPattern.test(ecrURL)) { | ||
const ecrPublic = new ECRPublic(region); | ||
authToken = await ecrPublic.fetchECRToken(); | ||
} | ||
|
||
await updateZarfManagedImageSecrets(ecrURL, authToken); | ||
} catch (err) { | ||
Log.error( | ||
`Error: unable to update ECR token in Zarf image pull secrets: ${err}`, | ||
); | ||
return; | ||
} | ||
} | ||
|
||
async function getECRURL(): Promise<string> { | ||
try { | ||
const secret = await getSecret(zarfNamespace, zarfStateSecret); | ||
const secretString = atob(secret.data!.state); | ||
const zarfState: ZarfState = JSON.parse(secretString); | ||
return zarfState.registryInfo.address; | ||
} catch (err) { | ||
Log.error(`unable to get ECR URL from ${zarfStateSecret} secret: ${err}`); | ||
return ""; | ||
} | ||
} | ||
|
||
async function updateZarfManagedImageSecrets( | ||
ecrURL: string, | ||
authToken: string, | ||
): Promise<void> { | ||
try { | ||
const namespaces = await listNamespaces(); | ||
|
||
for (const ns of namespaces) { | ||
const registrySecret = await getSecret( | ||
ns.metadata!.name!, | ||
zarfImagePullSecret, | ||
); | ||
|
||
// Check if this is a Zarf managed secret or is in a namespace the Zarf agent will take action in | ||
if ( | ||
registrySecret.metadata!.labels && | ||
(registrySecret.metadata!.labels[zarfManagedByLabel] === "zarf" || | ||
(ns.metadata!.labels && | ||
ns.metadata!.labels[zarfAgentLabel] !== "skip" && | ||
ns.metadata!.labels[zarfAgentLabel] !== "ignore")) | ||
) { | ||
// Update the secret with the new ECR auth token | ||
const dockerConfigJSON = { | ||
Auths: { | ||
[ecrURL]: { | ||
Auth: authToken, | ||
}, | ||
}, | ||
}; | ||
const dockerConfigData = btoa(JSON.stringify(dockerConfigJSON)); | ||
registrySecret.data![".dockerconfigjson"] = dockerConfigData; | ||
|
||
const updatedRegistrySecret = await updateSecret( | ||
ns.metadata!.name!, | ||
zarfImagePullSecret, | ||
registrySecret.data!.data, | ||
); | ||
|
||
Log.info( | ||
`Successfully updated secret '${ | ||
updatedRegistrySecret.metadata!.name | ||
}' in namespace '${ns.metadata!.name}'`, | ||
); | ||
} | ||
} | ||
} catch (err) { | ||
Log.error(`"unable to update secret Zarf image pull secret: ${err}`); | ||
return; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { K8s, kind } from "pepr"; | ||
|
||
export async function getSecret( | ||
ns: string, | ||
secretName: string, | ||
): Promise<kind.Secret> { | ||
return await K8s(kind.Secret).InNamespace(ns).Get(secretName); | ||
} | ||
|
||
export async function updateSecret( | ||
ns: string, | ||
secretName: string, | ||
secretData: string, | ||
): Promise<kind.Secret> { | ||
// Use Server-Side force apply to forcefully take ownership of the package secret data.data field | ||
return await K8s(kind.Secret).Apply( | ||
{ | ||
metadata: { | ||
name: secretName, | ||
namespace: ns, | ||
}, | ||
data: { | ||
data: secretData, | ||
}, | ||
}, | ||
{ force: true }, | ||
); | ||
} | ||
|
||
export async function listNamespaces(): Promise<kind.Namespace[]> { | ||
const ns = await K8s(kind.Namespace).Get(); | ||
return ns.items; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
import { PeprModule } from "pepr"; | ||
// cfg loads your pepr configuration from package.json | ||
import cfg from "./package.json"; | ||
import { ECRhook } from "./capabilities/ecr-webhook/webhook"; | ||
// import { ECRhook } from "./capabilities/ecr-webhook/webhook"; | ||
import { ECRCredentialHelper } from "./capabilities/ecr-credential-helper/credential-helper"; | ||
|
||
/** | ||
* This is the main entrypoint for this Pepr module. It is run when the module is started. | ||
* This is where you register your Pepr configurations and capabilities. | ||
*/ | ||
new PeprModule(cfg, [ECRhook, ECRCredentialHelper]); | ||
new PeprModule(cfg, [ | ||
// ECRhook, | ||
ECRCredentialHelper, | ||
]); |