|
|
|
@ -81,46 +81,47 @@ var kc kube.Client
|
|
|
|
|
// ensure that tailscale state storage and authentication mechanism will work on
|
|
|
|
|
// Kubernetes.
|
|
|
|
|
func (cfg *settings) setupKube(ctx context.Context) error {
|
|
|
|
|
if cfg.KubeSecret != "" {
|
|
|
|
|
canPatch, canCreate, err := kc.CheckSecretPermissions(ctx, cfg.KubeSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("Some Kubernetes permissions are missing, please check your RBAC configuration: %v", err)
|
|
|
|
|
}
|
|
|
|
|
cfg.KubernetesCanPatch = canPatch
|
|
|
|
|
if cfg.KubeSecret == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
canPatch, canCreate, err := kc.CheckSecretPermissions(ctx, cfg.KubeSecret)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("Some Kubernetes permissions are missing, please check your RBAC configuration: %v", err)
|
|
|
|
|
}
|
|
|
|
|
cfg.KubernetesCanPatch = canPatch
|
|
|
|
|
|
|
|
|
|
s, err := kc.GetSecret(ctx, cfg.KubeSecret)
|
|
|
|
|
if err != nil && kube.IsNotFoundErr(err) && !canCreate {
|
|
|
|
|
return fmt.Errorf("Tailscale state Secret %s does not exist and we don't have permissions to create it. "+
|
|
|
|
|
"If you intend to store tailscale state elsewhere than a Kubernetes Secret, "+
|
|
|
|
|
"you can explicitly set TS_KUBE_SECRET env var to an empty string. "+
|
|
|
|
|
"Else ensure that RBAC is set up that allows the service account associated with this installation to create Secrets.", cfg.KubeSecret)
|
|
|
|
|
} else if err != nil && !kube.IsNotFoundErr(err) {
|
|
|
|
|
return fmt.Errorf("Getting Tailscale state Secret %s: %v", cfg.KubeSecret, err)
|
|
|
|
|
}
|
|
|
|
|
s, err := kc.GetSecret(ctx, cfg.KubeSecret)
|
|
|
|
|
if err != nil && kube.IsNotFoundErr(err) && !canCreate {
|
|
|
|
|
return fmt.Errorf("Tailscale state Secret %s does not exist and we don't have permissions to create it. "+
|
|
|
|
|
"If you intend to store tailscale state elsewhere than a Kubernetes Secret, "+
|
|
|
|
|
"you can explicitly set TS_KUBE_SECRET env var to an empty string. "+
|
|
|
|
|
"Else ensure that RBAC is set up that allows the service account associated with this installation to create Secrets.", cfg.KubeSecret)
|
|
|
|
|
} else if err != nil && !kube.IsNotFoundErr(err) {
|
|
|
|
|
return fmt.Errorf("Getting Tailscale state Secret %s: %v", cfg.KubeSecret, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cfg.AuthKey == "" && !isOneStepConfig(cfg) {
|
|
|
|
|
if s == nil {
|
|
|
|
|
log.Print("TS_AUTHKEY not provided and kube secret does not exist, login will be interactive if needed.")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
keyBytes, _ := s.Data["authkey"]
|
|
|
|
|
key := string(keyBytes)
|
|
|
|
|
if cfg.AuthKey == "" && !isOneStepConfig(cfg) {
|
|
|
|
|
if s == nil {
|
|
|
|
|
log.Print("TS_AUTHKEY not provided and kube secret does not exist, login will be interactive if needed.")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
keyBytes, _ := s.Data["authkey"]
|
|
|
|
|
key := string(keyBytes)
|
|
|
|
|
|
|
|
|
|
if key != "" {
|
|
|
|
|
// This behavior of pulling authkeys from kube secrets was added
|
|
|
|
|
// at the same time as the patch permission, so we can enforce
|
|
|
|
|
// that we must be able to patch out the authkey after
|
|
|
|
|
// authenticating if you want to use this feature. This avoids
|
|
|
|
|
// us having to deal with the case where we might leave behind
|
|
|
|
|
// an unnecessary reusable authkey in a secret, like a rake in
|
|
|
|
|
// the grass.
|
|
|
|
|
if !cfg.KubernetesCanPatch {
|
|
|
|
|
return errors.New("authkey found in TS_KUBE_SECRET, but the pod doesn't have patch permissions on the secret to manage the authkey.")
|
|
|
|
|
}
|
|
|
|
|
cfg.AuthKey = key
|
|
|
|
|
} else {
|
|
|
|
|
log.Print("No authkey found in kube secret and TS_AUTHKEY not provided, login will be interactive if needed.")
|
|
|
|
|
if key != "" {
|
|
|
|
|
// This behavior of pulling authkeys from kube secrets was added
|
|
|
|
|
// at the same time as the patch permission, so we can enforce
|
|
|
|
|
// that we must be able to patch out the authkey after
|
|
|
|
|
// authenticating if you want to use this feature. This avoids
|
|
|
|
|
// us having to deal with the case where we might leave behind
|
|
|
|
|
// an unnecessary reusable authkey in a secret, like a rake in
|
|
|
|
|
// the grass.
|
|
|
|
|
if !cfg.KubernetesCanPatch {
|
|
|
|
|
return errors.New("authkey found in TS_KUBE_SECRET, but the pod doesn't have patch permissions on the secret to manage the authkey.")
|
|
|
|
|
}
|
|
|
|
|
cfg.AuthKey = key
|
|
|
|
|
} else {
|
|
|
|
|
log.Print("No authkey found in kube secret and TS_AUTHKEY not provided, login will be interactive if needed.")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|