feat(jar): add OCI registry pull for JAR artifacts with backward compat
- Add jarRef and jarPullSecret fields to FlinkJob CRD (jarUri/basicAuth deprecated) - OCI pull via go-containerregistry with dual auth (K8s pull secret + env vars) - Media type validation on pulled layers - Atomic status patches with runningJarRef/runningJarDigest tracking - NeedsUpgrade/RunningRef/RunningRefPatchData domain helpers - README with usage guide, pushing JARs, and GitHub Actions CI/CD workflow - CONTEXT.md domain glossary
This commit is contained in:
83
internal/crd/auth.go
Normal file
83
internal/crd/auth.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
type dockerConfigJSON struct {
|
||||
Auths map[string]authn.AuthConfig `json:"auths"`
|
||||
}
|
||||
|
||||
// ResolveAuth returns an OCI authenticator for the given registry.
|
||||
// It checks in order: pull secret from K8s, then environment variables.
|
||||
// Returns authn.Anonymous if no credentials are found.
|
||||
func (crd *Crd) ResolveAuth(pullSecretName string, server string) (authn.Authenticator, error) {
|
||||
if pullSecretName != "" {
|
||||
return crd.authFromPullSecret(pullSecretName, server)
|
||||
}
|
||||
return authFromEnv(server), nil
|
||||
}
|
||||
|
||||
func (crd *Crd) authFromPullSecret(secretName string, server string) (authn.Authenticator, error) {
|
||||
ns := os.Getenv("NAMESPACE")
|
||||
secret := &corev1.Secret{}
|
||||
err := crd.runtimeClient.Get(context.Background(), types.NamespacedName{
|
||||
Namespace: ns,
|
||||
Name: secretName,
|
||||
}, secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading pull secret %q: %w", secretName, err)
|
||||
}
|
||||
|
||||
if secret.Type != corev1.SecretTypeDockerConfigJson {
|
||||
return nil, fmt.Errorf("secret %q is not of type kubernetes.io/dockerconfigjson", secretName)
|
||||
}
|
||||
|
||||
dockerConfigJSONBytes, ok := secret.Data[corev1.DockerConfigJsonKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("secret %q missing .dockerconfigjson key", secretName)
|
||||
}
|
||||
|
||||
var cfg dockerConfigJSON
|
||||
if err := json.Unmarshal(dockerConfigJSONBytes, &cfg); err != nil {
|
||||
return nil, fmt.Errorf("parsing docker config from secret %q: %w", secretName, err)
|
||||
}
|
||||
|
||||
if server != "" {
|
||||
if entry, ok := cfg.Auths[server]; ok {
|
||||
return authn.FromConfig(entry), nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range cfg.Auths {
|
||||
return authn.FromConfig(entry), nil
|
||||
}
|
||||
|
||||
return authn.Anonymous, nil
|
||||
}
|
||||
|
||||
func authFromEnv(server string) authn.Authenticator {
|
||||
username := os.Getenv("REGISTRY_USERNAME")
|
||||
password := os.Getenv("REGISTRY_PASSWORD")
|
||||
envServer := os.Getenv("REGISTRY_SERVER")
|
||||
|
||||
if username == "" || password == "" {
|
||||
return authn.Anonymous
|
||||
}
|
||||
|
||||
if envServer != "" && server != "" && envServer != server {
|
||||
return authn.Anonymous
|
||||
}
|
||||
|
||||
return authn.FromConfig(authn.AuthConfig{
|
||||
Username: username,
|
||||
Password: password,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user