Skip to content

Conversation

@ielshal
Copy link

@ielshal ielshal commented Nov 12, 2025

Summary

We are using rexec for recorded access for containers inside k8s clusters, we are also going to need to have copy functionality, kubectl cp is depending on exec, so we need to implement our own copy with rexec.

Below is what we are introducing in this PR,

  • Implement kubectl rexec cp for audited file transfers
  • Add tests for cp functionality
  • Update documentation with cp command examples

Tested scenarios

Unit Testing output

cd plugin && go test -v
=== RUN   TestParseFileSpec
=== RUN   TestParseFileSpec/local_file
=== RUN   TestParseFileSpec/pod_file
=== RUN   TestParseFileSpec/pod_file_with_namespace
=== RUN   TestParseFileSpec/invalid_spec_-_multiple_colons
--- PASS: TestParseFileSpec (0.00s)
    --- PASS: TestParseFileSpec/local_file (0.00s)
    --- PASS: TestParseFileSpec/pod_file (0.00s)
    --- PASS: TestParseFileSpec/pod_file_with_namespace (0.00s)
    --- PASS: TestParseFileSpec/invalid_spec_-_multiple_colons (0.00s)
=== RUN   TestIsDestDir
=== RUN   TestIsDestDir/path_with_trailing_slash
=== RUN   TestIsDestDir/existing_directory
=== RUN   TestIsDestDir/non-existing_path
--- PASS: TestIsDestDir (0.00s)
    --- PASS: TestIsDestDir/path_with_trailing_slash (0.00s)
    --- PASS: TestIsDestDir/existing_directory (0.00s)
    --- PASS: TestIsDestDir/non-existing_path (0.00s)
=== RUN   TestCreateTarSingleFile
--- PASS: TestCreateTarSingleFile (0.00s)
=== RUN   TestCreateTarDirectory
--- PASS: TestCreateTarDirectory (0.00s)
=== RUN   TestExtractTar
--- PASS: TestExtractTar (0.00s)
=== RUN   TestExtractTarPathTraversal
--- PASS: TestExtractTarPathTraversal (0.00s)
=== RUN   TestRunWithArgsValidation
=== RUN   TestRunWithArgsValidation/pod_to_pod_-_not_supported
--- PASS: TestRunWithArgsValidation (0.00s)
    --- PASS: TestRunWithArgsValidation/pod_to_pod_-_not_supported (0.00s)
PASS
ok      github.com/adyen/kubectl-rexec/plugin   0.605s

❯ cd -                   
~/code/github.com/adyen/kubectl-rexec

❯ cd rexec/server && go test -v
=== RUN   TestExecHandlerUnsupportedContentType
--- PASS: TestExecHandlerUnsupportedContentType (0.00s)
=== RUN   TestExecHandlerBadJSON
--- PASS: TestExecHandlerBadJSON (0.00s)
=== RUN   TestExecHandlerAllowsNonExecKinds
--- PASS: TestExecHandlerAllowsNonExecKinds (0.00s)
=== RUN   TestExecHandlerBypassedUser
--- PASS: TestExecHandlerBypassedUser (0.00s)
=== RUN   TestExecHandlerSecretSauce
--- PASS: TestExecHandlerSecretSauce (0.00s)
=== RUN   TestExecHandlerExecDenied
--- PASS: TestExecHandlerExecDenied (0.00s)
=== RUN   TestCanPassBypassUser
--- PASS: TestCanPassBypassUser (0.00s)
=== RUN   TestCanPassSecretSauceMatch
--- PASS: TestCanPassSecretSauceMatch (0.00s)
=== RUN   TestCanPassNoMatch
--- PASS: TestCanPassNoMatch (0.00s)
=== RUN   TestWaitForListenerReady
--- PASS: TestWaitForListenerReady (0.00s)
=== RUN   TestRexecHandlerMissingUser
--- PASS: TestRexecHandlerMissingUser (0.00s)
PASS
ok      github.com/adyen/kubectl-rexec/rexec/server     0.208s

Manual Testing Done

Setup Test Environment using kind locally

# 1. Create Kind cluster
kind create cluster --name rexec-test --image kindest/node:v1.30.0

# 2. Build and load image
docker build -t kubectl-rexec:test .
kind load docker-image kubectl-rexec:test --name rexec-test

# 3. Deploy with test image
cd manifests
kustomize edit set image ghcr.io/adyen/kubectl-rexec:latest=kubectl-rexec:test
kubectl apply -k . --context kind-rexec-test

# 4. Build plugin
go build -o kubectl-rexec main.go
chmod +x kubectl-rexec

Test Cases

1. Basic Exec
kubectl run test-pod --image=ubuntu:22.04 -- sleep 3600

./kubectl-rexec exec test-pod -- echo "hello"
kubectl -n kube-system logs -l app=rexec --tail=5
2. File Upload
echo "test content" > /tmp/test.txt
./kubectl-rexec cp /tmp/test.txt test-pod:/tmp/test.txt

# Verify
./kubectl-rexec exec test-pod -- cat /tmp/test.txt

# Check audit logs
kubectl -n kube-system logs -l app=rexec --tail=10 | grep tar
3. File Download
./kubectl-rexec exec test-pod -- sh -c 'echo "from pod" > /tmp/download.txt'
./kubectl-rexec cp test-pod:/tmp/download.txt /tmp/download.txt
cat /tmp/download.txt
4. Directory Copy
mkdir -p /tmp/testdir/sub
echo "file1" > /tmp/testdir/file1.txt
echo "file2" > /tmp/testdir/sub/file2.txt

./kubectl-rexec cp /tmp/testdir test-pod:/tmp/uploaded
./kubectl-rexec exec test-pod -- ls -R /tmp/uploaded
./kubectl-rexec exec test-pod -- cat /tmp/uploaded/sub/file2.txt
5. Multi-Container Pod
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: multi-pod
spec:
  containers:
  - name: c1
    image: ubuntu:22.04
    command: ["sleep", "3600"]
  - name: c2
    image: ubuntu:22.04
    command: ["sleep", "3600"]
EOF

kubectl wait --for=condition=ready pod/multi-pod --timeout=60s

# Must use -c flag
./kubectl-rexec cp /tmp/test.txt multi-pod:/tmp/test.txt -c c2
./kubectl-rexec exec multi-pod -c c2 -- cat /tmp/test.txt

Verify Audit Logs

Expected log format:

{
  "level": "info",
  "facility": "audit",
  "user": "kubernetes-admin",
  "session": "oneoff",
  "command": "tar xf - -C /tmp",
  "time": "2024-12-16T10:30:01Z"
}

Which indeed what we get when we checked logs,

kubectl -n kube-system logs -l app=rexec --context kind-rexec-test --tail=20 | grep tar

{"level":"info","facility":"audit","user":"kubernetes-admin","session":"oneoff","command":"tar xf - -C /tmp","time":"2025-11-12T01:34:40Z"}
{"level":"info","facility":"audit","user":"kubernetes-admin","session":"oneoff","command":"tar cf - /tmp/from-pod.txt","time":"2025-11-12T01:35:21Z"}
{"level":"info","facility":"audit","user":"kubernetes-admin","session":"oneoff","command":"tar xf - -C /tmp","time":"2025-11-12T01:37:14Z"}
{"level":"info","facility":"audit","user":"kubernetes-admin","session":"oneoff","command":"tar cf - /tmp/uploaded-dir","time":"2025-11-12T01:37:41Z"}
{"level":"info","facility":"audit","user":"kubernetes-admin","session":"oneoff","command":"tar xf - -C /tmp","time":"2025-11-12T01:38:28Z"}

Cleanup

kubectl delete pod test-pod multi-pod
kubectl delete namespace test-ns
kind delete cluster --name rexec-test
rm -f /tmp/test.txt /tmp/download.txt
rm -rf /tmp/testdir

Fixed issue:

  • As mentioned we are introducing new feature so nothing to be fixed, the idea is to implement kubectl cp using rexec.

@ielshal ielshal requested a review from a team as a code owner November 12, 2025 22:15
- Implement kubectl rexec cp for audited file transfers
- Add tests for cp functionality
- Update documentation with cp command examples
@ielshal ielshal force-pushed the ibrahim/implemenet-copy-command-into-kubectl-rexec branch from 22f5266 to 17a06a7 Compare November 13, 2025 16:02
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant