in gce_workload_cert_refresh/main.go [251:335]
func refreshCreds(ctx context.Context, opts outputOpts) error {
now := timeNow()
contentDir := fmt.Sprintf("%s-%s", opts.contentDirPrefix, now)
tempSymlink := fmt.Sprintf("%s-%s", opts.tempSymlinkPrefix, now)
// Get status first so it can be written even when other endpoints are empty.
certConfigStatus, err := getMetadata(ctx, configStatusKey)
if err != nil {
// Return success when certs are not configured to avoid unnecessary systemd failed units.
logger.Infof("Error getting config status, workload certificates may not be configured: %v", err)
return nil
}
logger.Infof("Creating timestamp contents dir %s", contentDir)
if err := os.MkdirAll(contentDir, 0755); err != nil {
return fmt.Errorf("error creating contents dir: %v", err)
}
// Write config_status first even if remaining endpoints are empty.
if err := os.WriteFile(filepath.Join(contentDir, "config_status"), certConfigStatus, 0644); err != nil {
return fmt.Errorf("error writing config_status: %v", err)
}
// Handles the edge case where the config values provided for the first time may be invalid. This ensures
// that the symlink directory always exists and contains the config_status to surface config errors to the VM.
if _, err := os.Stat(opts.symlink); os.IsNotExist(err) {
logger.Infof("Creating new symlink %s", symlink)
if err := os.Symlink(contentDir, opts.symlink); err != nil {
return fmt.Errorf("error creating symlink: %v", err)
}
}
// Now get the rest of the content.
wisMd, err := getMetadata(ctx, workloadIdentitiesKey)
if err != nil {
return fmt.Errorf("error getting workload-identities: %v", err)
}
spiffeID, err := writeWorkloadIdentities(contentDir, wisMd)
if err != nil {
return fmt.Errorf("failed to write workload identities with error: %w", err)
}
wtrcsMd, err := getMetadata(ctx, trustAnchorsKey)
if err != nil {
return fmt.Errorf("error getting workload-trust-anchors: %v", err)
}
if err := writeTrustAnchors(wtrcsMd, contentDir, spiffeID); err != nil {
return fmt.Errorf("failed to write trust anchors: %w", err)
}
if err := os.Symlink(contentDir, tempSymlink); err != nil {
return fmt.Errorf("error creating temporary link: %v", err)
}
oldTarget, err := os.Readlink(opts.symlink)
if err != nil {
logger.Infof("Error reading existing symlink: %v\n", err)
oldTarget = ""
}
// Only rotate on success of all steps above.
logger.Infof("Rotating symlink %s", opts.symlink)
if err := os.Rename(tempSymlink, opts.symlink); err != nil {
return fmt.Errorf("error rotating target link: %v", err)
}
// Clean up previous contents dir.
newTarget, err := os.Readlink(opts.symlink)
if err != nil {
return fmt.Errorf("error reading new symlink: %v, unable to remove old symlink target", err)
}
if oldTarget != newTarget {
logger.Infof("Removing old content dir %s", oldTarget)
if err := os.RemoveAll(oldTarget); err != nil {
return fmt.Errorf("failed to remove old symlink target: %v", err)
}
}
return nil
}