Skip to content

Commit

Permalink
Merge pull request #205 from renoki-co/feature/cmd-auth
Browse files Browse the repository at this point in the history
[fix] Added support for cmd-like auth
  • Loading branch information
rennokki authored Mar 7, 2022
2 parents 8027fec + 52f1769 commit 52039c5
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 18 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"illuminate/macroable": "^8.83|^9.0.1",
"illuminate/support": "^8.83|^9.0.1",
"ratchet/pawl": "^0.4.1",
"symfony/process": "^5.4|^6.0",
"vierbergenlars/php-semver": "^2.1|^3.0"
},
"suggest": {
Expand Down
2 changes: 1 addition & 1 deletion src/Kinds/K8sPod.php
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ public function getInitContainerStatuses(bool $asInstance = true): array
*
* @param string $containerName
* @param bool $asInstance
* @return array|null
* @return \RenokiCo\PhpK8s\Instances\Container|array|null
*/
public function getContainer(string $containerName, bool $asInstance = true)
{
Expand Down
33 changes: 33 additions & 0 deletions src/Traits/Cluster/AuthenticatesCluster.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace RenokiCo\PhpK8s\Traits\Cluster;

use Illuminate\Support\Arr;
use RenokiCo\PhpK8s\Kinds\K8sResource;
use Symfony\Component\Process\Process;

trait AuthenticatesCluster
{
Expand Down Expand Up @@ -70,6 +72,37 @@ public function withToken(string $token = null)
return $this;
}

/**
* Load the token from provider command line.
*
* @param string $cmdPath
* @param string|nll $cmdArgs
* @param string|null $tokenPath
* @return $this
*/
public function withTokenFromCommandProvider(string $cmdPath, string $cmdArgs = null, string $tokenPath = null)
{
$process = Process::fromShellCommandline("{$cmdPath} {$cmdArgs}");

$process->run();

if ($process->getErrorOutput()) {
return $this;
}

$output = $process->getOutput();

if (! $tokenPath) {
return $this->withToken(trim($output));
}

$json = json_decode($output, true);

return $this->withToken(
trim(Arr::get($json, str_replace(['{.', '}'], '', $tokenPath)))
);
}

/**
* Load a Bearer Token from file.
*
Expand Down
10 changes: 10 additions & 0 deletions src/Traits/Cluster/LoadsFromKubeConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,16 @@ protected function loadKubeConfigFromArray(array $kubeconfig, string $context =
$this->withToken($userConfig['user']['auth-provider']['config']['access-token']);
}

if (isset($userConfig['user']['auth-provider']['config']['cmd-path'])) {
$authProviderConfig = $userConfig['user']['auth-provider']['config'];

$this->withTokenFromCommandProvider(
$authProviderConfig['cmd-path'],
$authProviderConfig['cmd-args'] ?? null,
$authProviderConfig['token-key'] ?? null,
);
}

if (isset($clusterConfig['cluster']['insecure-skip-tls-verify']) && $clusterConfig['cluster']['insecure-skip-tls-verify']) {
$this->withoutSslChecks();
}
Expand Down
1 change: 1 addition & 0 deletions src/Traits/Cluster/MakesHttpCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function getClient()
$options = [
RequestOptions::HEADERS => [
'Content-Type' => 'application/json',
'Accept-Encoding' => 'gzip, deflate',
],
RequestOptions::VERIFY => true,
];
Expand Down
24 changes: 12 additions & 12 deletions tests/ClusterRoleBindingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function test_cluster_role_binding_build()
->addVerbs(['get', 'list', 'watch']);

$cr = $this->cluster->clusterRole()
->setName('admin-cr')
->setName('admin-cr-for-binding')
->setLabels(['tier' => 'backend'])
->addRules([$rule]);

Expand All @@ -39,7 +39,7 @@ public function test_cluster_role_binding_build()
$this->assertEquals('user-binding', $crb->getName());
$this->assertEquals(['tier' => 'backend'], $crb->getLabels());
$this->assertEquals([$subject], $crb->getSubjects());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr'], $crb->getRole());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr-for-binding'], $crb->getRole());
}

public function test_cluster_role_binding_from_yaml()
Expand All @@ -51,7 +51,7 @@ public function test_cluster_role_binding_from_yaml()
->addVerbs(['get', 'list', 'watch']);

$cr = $this->cluster->clusterRole()
->setName('admin-cr')
->setName('admin-cr-for-binding')
->setLabels(['tier' => 'backend'])
->addRules([$rule]);

Expand All @@ -66,7 +66,7 @@ public function test_cluster_role_binding_from_yaml()
$this->assertEquals('user-binding', $crb->getName());
$this->assertEquals(['tier' => 'backend'], $crb->getLabels());
$this->assertEquals([$subject], $crb->getSubjects());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr'], $crb->getRole());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr-for-binding'], $crb->getRole());
}

public function test_cluster_role_binding_api_interaction()
Expand All @@ -89,7 +89,7 @@ public function runCreationTests()
->addVerbs(['get', 'list', 'watch']);

$cr = $this->cluster->clusterRole()
->setName('admin-cr')
->setName('admin-cr-for-binding')
->setLabels(['tier' => 'backend'])
->addRules([$rule]);

Expand Down Expand Up @@ -120,7 +120,7 @@ public function runCreationTests()
$this->assertEquals('user-binding', $crb->getName());
$this->assertEquals(['tier' => 'backend'], $crb->getLabels());
$this->assertEquals([$subject], $crb->getSubjects());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr'], $crb->getRole());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr-for-binding'], $crb->getRole());
}

public function runGetAllTests()
Expand All @@ -143,7 +143,7 @@ public function runGetTests()
->setKind('User')
->setName('user-1');

$cr = $this->cluster->getClusterRoleByName('admin-cr');
$cr = $this->cluster->getClusterRoleByName('admin-cr-for-binding');
$crb = $this->cluster->getClusterRoleBindingByName('user-binding');

$this->assertInstanceOf(K8sClusterRoleBinding::class, $crb);
Expand All @@ -154,12 +154,12 @@ public function runGetTests()
$this->assertEquals('user-binding', $crb->getName());
$this->assertEquals(['tier' => 'backend'], $crb->getLabels());
$this->assertEquals([$subject], $crb->getSubjects());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr'], $crb->getRole());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr-for-binding'], $crb->getRole());
}

public function runUpdateTests()
{
$cr = $this->cluster->getClusterRoleByName('admin-cr');
$cr = $this->cluster->getClusterRoleByName('admin-cr-for-binding');
$crb = $this->cluster->getClusterRoleBindingByName('user-binding');

$subject = K8s::subject()
Expand All @@ -179,12 +179,12 @@ public function runUpdateTests()
$this->assertEquals('user-binding', $crb->getName());
$this->assertEquals(['tier' => 'backend'], $crb->getLabels());
$this->assertEquals([$subject], $crb->getSubjects());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr'], $crb->getRole());
$this->assertEquals(['apiGroup' => 'rbac.authorization.k8s.io', 'kind' => 'ClusterRole', 'name' => 'admin-cr-for-binding'], $crb->getRole());
}

public function runDeletionTests()
{
$cr = $this->cluster->getClusterRoleByName('admin-cr');
$cr = $this->cluster->getClusterRoleByName('admin-cr-for-binding');
$crb = $this->cluster->getClusterRoleBindingByName('user-binding');

$this->assertTrue($cr->delete());
Expand All @@ -200,7 +200,7 @@ public function runDeletionTests()

$this->expectException(KubernetesAPIException::class);

$this->cluster->getClusterRoleByName('admin-cr');
$this->cluster->getClusterRoleByName('admin-cr-for-binding');
$this->cluster->getClusterRoleBindingByName('user-binding');
}

Expand Down
18 changes: 18 additions & 0 deletions tests/KubeConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,22 @@ public function test_kube_config_from_array_with_base64_encoded_ssl()
$this->assertEquals("some-cert\n", file_get_contents($certPath));
$this->assertEquals("some-key\n", file_get_contents($keyPath));
}

public function test_kube_config_from_yaml_file_with_cmd_auth_as_json()
{
$cluster = KubernetesCluster::fromKubeConfigYamlFile(__DIR__.'/cluster/kubeconfig-command.yaml', 'minikube');

['headers' => ['authorization' => $token]] = $cluster->getClient()->getConfig();

$this->assertEquals('Bearer some-token', $token);
}

public function test_kube_config_from_yaml_file_with_cmd_auth_as_string()
{
$cluster = KubernetesCluster::fromKubeConfigYamlFile(__DIR__.'/cluster/kubeconfig-command.yaml', 'minikube-2');

['headers' => ['authorization' => $token]] = $cluster->getClient()->getConfig();

$this->assertEquals('Bearer some-token', $token);
}
}
8 changes: 4 additions & 4 deletions tests/PodTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function test_pod_api_interaction()
public function test_pod_exec()
{
$busybox = K8s::container()
->setName('busybox')
->setName('busybox-exec')
->setImage('busybox')
->setCommand(['/bin/sh', '-c', 'sleep 7200']);

Expand All @@ -126,7 +126,7 @@ public function test_pod_exec()
$pod->refresh();
}

$messages = $pod->exec(['/bin/sh', '-c', 'echo 1 && echo 2 && echo 3'], 'busybox');
$messages = $pod->exec(['/bin/sh', '-c', 'echo 1 && echo 2 && echo 3'], 'busybox-exec');

$hasDesiredOutput = collect($messages)->where('channel', 'stdout')->filter(function ($message) {
return Str::contains($message['output'], '1')
Expand All @@ -142,15 +142,15 @@ public function test_pod_exec()
public function test_pod_attach()
{
$mysql = K8s::container()
->setName('mysql')
->setName('mysql-attach')
->setImage('mysql', '5.7')
->setPorts([
['name' => 'mysql', 'protocol' => 'TCP', 'containerPort' => 3306],
])
->setEnv(['MYSQL_ROOT_PASSWORD' => 'test']);

$pod = $this->cluster->pod()
->setName('mysql-exec')
->setName('mysql-attach')
->setContainers([$mysql])
->createOrUpdate();

Expand Down
35 changes: 35 additions & 0 deletions tests/cluster/kubeconfig-command.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: c29tZS1jYQo= # "some-ca"
server: https://minikube:8443
name: minikube
- cluster:
certificate-authority-data: c29tZS1jYQo= # "some-ca"
server: https://minikube:8443
name: minikube-2
contexts:
- context:
cluster: minikube
user: minikube
name: minikube
- context:
cluster: minikube-2
user: minikube-2
name: minikube-2
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
auth-provider:
config:
cmd-args: ''
cmd-path: cat tests/cluster/token.json
token-key: '{.nested.token}'
- name: minikube-2
user:
auth-provider:
config:
cmd-path: 'echo some-token'
5 changes: 5 additions & 0 deletions tests/cluster/token.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"nested": {
"token": "some-token"
}
}
2 changes: 1 addition & 1 deletion tests/yaml/clusterrolebinding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ metadata:
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin-cr
name: admin-cr-for-binding
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
Expand Down

0 comments on commit 52039c5

Please sign in to comment.