ArgoCD, Private GitHub Repos, and the AWS SSO Kubeconfig Problem
Two problems blocked our ArgoCD bootstrap: AWS SSO's login session config prevented kubectl from authenticating, and ArgoCD couldn't pull our private mypie-infra repo. Here is how we solved both.
After ArgoCD was installed via Helm, we tried to apply our root-app.yaml to bootstrap the App-of-Apps pattern. Two separate issues came up in sequence — one about kubectl itself not being able to talk to the cluster, and one about ArgoCD not being able to read from our private GitHub repository.
Problem 1: AWS SSO Kubeconfig Exec Plugin Failure
We use AWS IAM Identity Center (SSO) for authentication. The login flow is aws login (not aws sso login — Identity Center uses a different command). This command stores a short-lived token in ~/.aws/login/cache/*.json.
Our kubeconfig used the aws eks get-token exec plugin, which is the standard EKS setup:
users:
- name: arn:aws:eks:eu-central-1:<account-id>:cluster/mypie-eks-staging
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws
args:
- eks
- get-token
- --cluster-name
- mypie-eks-staging
- --region
- eu-central-1
Every kubectl command was failing:
error: exec plugin: invalid apiVersion "client.authentication.k8s.io/v1beta1"
And even after installing the right aws cli version, aws eks get-token was returning an expired/invalid token. The reason: aws login stores the session under a [login_session] profile in ~/.aws/config, and this profile takes precedence over environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) when the aws CLI is invoked by the exec plugin.
In other words: even if you exported your credentials into the shell environment, every time kubectl called aws eks get-token, the AWS CLI read ~/.aws/config, found the [login_session] profile, used that (which may be expired or point to a different assume-role chain), and ignored your environment variables.
The Fix: Static Token Patch
We bypassed the exec plugin entirely by extracting the token ourselves and patching the kubeconfig with a static bearer token. This script ran before every kubectl session:
import json, glob, subprocess, yaml, re
# Step 1: Read the cached access token from aws login
cache_files = glob.glob('/home/<user>/.aws/login/cache/*.json')
credentials = json.load(open(cache_files[0]))['accessToken']
env = {
'AWS_ACCESS_KEY_ID': credentials['accessKeyId'],
'AWS_SECRET_ACCESS_KEY': credentials['secretAccessKey'],
'AWS_SESSION_TOKEN': credentials['sessionToken'],
'AWS_DEFAULT_REGION': 'eu-central-1',
# Crucially: ignore the ~/.aws/config to prevent login_session override
'AWS_CONFIG_FILE': '/dev/null',
'HOME': '/home/<user>',
'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
}
# Step 2: Call get-token with credentials from env only (no config file)
result = subprocess.run(
['aws', 'eks', 'get-token',
'--cluster-name', 'mypie-eks-staging',
'--region', 'eu-central-1'],
env=env, capture_output=True, text=True
)
token = json.loads(result.stdout)['status']['token']
# Step 3: Patch kubeconfig — replace exec block with static token
kube_data = yaml.safe_load(open('/home/<user>/.kube/config').read())
for user in kube_data.get('users', []):
if 'staging' in user.get('name', ''):
user['user'] = {'token': token}
with open('/home/<user>/.kube/config', 'w') as f:
yaml.dump(kube_data, f, default_flow_style=False)
print("Kubeconfig patched with static token")
The key insight is AWS_CONFIG_FILE=/dev/null — this tells the AWS CLI in that subprocess to use no config file, so it reads credentials exclusively from environment variables. After patching, kubectl commands worked for the ~15-minute lifetime of the SSO token.
For production use: Set up a dedicated kubeconfig for CI/CD using an IRSA-based service account or a long-lived IAM user with EKS API access, rather than relying on SSO tokens.
Problem 2: ArgoCD “Repository Not Found”
With kubectl working, we applied the root app:
kubectl apply -f k8s/argocd/apps/root-app.yaml
ArgoCD accepted the resource but all applications immediately showed an error in the ArgoCD UI and via kubectl get applications:
ComparisonError: rpc error: code = Unknown
desc = repository not found or not accessible
The mypie-infra repository is private on GitHub. ArgoCD needed credentials to clone it.
Creating the Repository Secret
ArgoCD uses Kubernetes secrets with a specific label to discover repository credentials. We created the secret directly (we later templated this into a sealed-secret for GitOps safety):
kubectl create secret generic argocd-repo-secret \
--namespace argocd \
--from-literal=type=git \
--from-literal=url=https://github.com/<org>/mypie-infra \
--from-literal=username=<github-username> \
--from-literal=password=<github-personal-access-token>
# The label is required — without it ArgoCD won't use the secret
kubectl label secret argocd-repo-secret \
-n argocd \
argocd.argoproj.io/secret-type=repository
The PAT needs the repo scope (read access to private repositories). After applying the label, ArgoCD picked up the secret within a few seconds and retried the repo connection. The error cleared and applications transitioned to their correct sync states.
Alternative: SSH Key
If you prefer SSH over HTTPS:
# Generate a deploy key (no passphrase for automated use)
ssh-keygen -t ed25519 -f /tmp/argocd-deploy-key -N ""
# Add the public key as a deploy key in GitHub repo settings
cat /tmp/argocd-deploy-key.pub
# Create the ArgoCD secret
kubectl create secret generic argocd-repo-secret \
--namespace argocd \
--from-literal=type=git \
--from-literal=url=git@github.com:<org>/mypie-infra.git \
--from-file=sshPrivateKey=/tmp/argocd-deploy-key
kubectl label secret argocd-repo-secret \
-n argocd \
argocd.argoproj.io/secret-type=repository
The Token Expiry Problem
The SSO token from aws login expires every ~15 minutes. This means the kubeconfig patch needs to be re-run each session. A practical approach for a workstation:
# Add to .bashrc or .zshrc
function kube-refresh-staging() {
python3 /path/to/patch-kubeconfig.py
echo "Kubeconfig refreshed"
}
# Or as an alias that auto-refreshes before any kubectl command
# (more complex, requires shell hooks)
For CI/CD environments, the proper solution is a Kubernetes service account with a long-lived token or IRSA with an assume-role that has eks:DescribeCluster + in-cluster RBAC bindings — avoiding SSO entirely.