Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Azure #57

Merged
merged 4 commits into from
Feb 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion cmds/initclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ func NewCmdInitClient() *cobra.Command {
}
}
if len(args) == 0 {
log.Fatalln("Missing client name.")
if strings.ToLower(org) == "azure" {
//azure common name not required, so default common name used
args = []string{"azure"}
} else {
log.Fatalln("Missing client name.")
}
}
if len(args) > 1 {
log.Fatalln("Multiple client name found.")
Expand All @@ -53,6 +58,8 @@ func NewCmdInitClient() *cobra.Command {
cfg.Organization = []string{"Appscode"}
case "gitlab":
cfg.Organization = []string{"Gitlab"}
case "azure":
cfg.Organization = []string{"Azure"}
case "":
log.Fatalln("Missing organization name. Set flag -o Google|Github.")
default:
Expand Down
77 changes: 48 additions & 29 deletions cmds/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,22 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)

type options struct {
namespace string
addr string
enableRBAC bool
tokenAuthFile string
Azure lib.AzureOpts
}

func NewCmdInstaller() *cobra.Command {
var (
namespace string
addr string
enableRBAC bool
tokenAuthFile string
)
var opts options
cmd := &cobra.Command{
Use: "installer",
Short: "Prints Kubernetes objects for deploying guard server",
DisableAutoGenTag: true,
Run: func(cmd *cobra.Command, args []string) {
_, port, err := net.SplitHostPort(addr)
_, port, err := net.SplitHostPort(opts.addr)
if err != nil {
log.Fatalf("Guard server address is invalid. Reason: %v.", err)
}
Expand Down Expand Up @@ -69,71 +72,71 @@ func NewCmdInstaller() *cobra.Command {
var buf bytes.Buffer
var data []byte

if namespace != "kube-system" && namespace != core.NamespaceDefault {
data, err = meta.MarshalToYAML(newNamespace(namespace), core.SchemeGroupVersion)
if opts.namespace != "kube-system" && opts.namespace != core.NamespaceDefault {
data, err = meta.MarshalToYAML(newNamespace(opts.namespace), core.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")
}

if enableRBAC {
data, err = meta.MarshalToYAML(newServiceAccount(namespace), core.SchemeGroupVersion)
if opts.enableRBAC {
data, err = meta.MarshalToYAML(newServiceAccount(opts.namespace), core.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")

data, err = meta.MarshalToYAML(newClusterRole(namespace), rbac.SchemeGroupVersion)
data, err = meta.MarshalToYAML(newClusterRole(opts.namespace), rbac.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")

data, err = meta.MarshalToYAML(newClusterRoleBinding(namespace), rbac.SchemeGroupVersion)
data, err = meta.MarshalToYAML(newClusterRoleBinding(opts.namespace), rbac.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")
}

data, err = meta.MarshalToYAML(newSecret(namespace, serverCert, serverKey, caCert), core.SchemeGroupVersion)
data, err = meta.MarshalToYAML(newSecret(opts.namespace, serverCert, serverKey, caCert), core.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")

if tokenAuthFile != "" {
_, err := lib.LoadTokenFile(tokenAuthFile)
if opts.tokenAuthFile != "" {
_, err := lib.LoadTokenFile(opts.tokenAuthFile)
if err != nil {
log.Fatalln(err)
}
tokenData, err := ioutil.ReadFile(tokenAuthFile)
tokenData, err := ioutil.ReadFile(opts.tokenAuthFile)
if err != nil {
log.Fatalln(err)
}
data, err = meta.MarshalToYAML(newSecretForTokenAuth(namespace, tokenData), core.SchemeGroupVersion)
data, err = meta.MarshalToYAML(newSecretForTokenAuth(opts.namespace, tokenData), core.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")
}

enableTokenAuth := tokenAuthFile != ""
data, err = meta.MarshalToYAML(newDeployment(namespace, enableRBAC, enableTokenAuth), apps.SchemeGroupVersion)
data, err = meta.MarshalToYAML(newDeployment(opts), apps.SchemeGroupVersion)

if err != nil {
log.Fatalln(err)
}
buf.Write(data)
buf.WriteString("---\n")

data, err = meta.MarshalToYAML(newService(namespace, addr), core.SchemeGroupVersion)
data, err = meta.MarshalToYAML(newService(opts.namespace, opts.addr), core.SchemeGroupVersion)
if err != nil {
log.Fatalln(err)
}
Expand All @@ -144,10 +147,13 @@ func NewCmdInstaller() *cobra.Command {
}

cmd.Flags().StringVar(&rootDir, "pki-dir", rootDir, "Path to directory where pki files are stored.")
cmd.Flags().StringVarP(&namespace, "namespace", "n", "kube-system", "Name of Kubernetes namespace used to run guard server.")
cmd.Flags().StringVar(&addr, "addr", "10.96.10.96:9844", "Address (host:port) of guard server.")
cmd.Flags().BoolVar(&enableRBAC, "rbac", enableRBAC, "If true, uses RBAC with operator and database objects")
cmd.Flags().StringVar(&tokenAuthFile, "token-auth-file", "", "Path to the token file")
cmd.Flags().StringVarP(&opts.namespace, "namespace", "n", "kube-system", "Name of Kubernetes namespace used to run guard server.")
cmd.Flags().StringVar(&opts.addr, "addr", "10.96.10.96:9844", "Address (host:port) of guard server.")
cmd.Flags().BoolVar(&opts.enableRBAC, "rbac", opts.enableRBAC, "If true, uses RBAC with operator and database objects")
cmd.Flags().StringVar(&opts.tokenAuthFile, "token-auth-file", "", "Path to the token file")
cmd.Flags().StringVar(&opts.Azure.ClientID, "azure.client-id", opts.Azure.ClientID, "MS Graph application client ID to use")
cmd.Flags().StringVar(&opts.Azure.ClientSecret, "azure.client-secret", opts.Azure.ClientSecret, "MS Graph application client secret to use")
cmd.Flags().StringVar(&opts.Azure.TenantID, "azure.tenant-id", opts.Azure.TenantID, "MS Graph application tenant id to use")
return cmd
}

Expand Down Expand Up @@ -179,11 +185,11 @@ func newSecret(namespace string, cert, key, caCert []byte) runtime.Object {
}
}

func newDeployment(namespace string, enableRBAC, enableTokenAuth bool) runtime.Object {
func newDeployment(opts options) runtime.Object {
d := apps.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "guard",
Namespace: namespace,
Namespace: opts.namespace,
Labels: labels,
},
Spec: apps.DeploymentSpec{
Expand Down Expand Up @@ -239,10 +245,11 @@ func newDeployment(namespace string, enableRBAC, enableTokenAuth bool) runtime.O
},
},
}
if enableRBAC {
if opts.enableRBAC {
d.Spec.Template.Spec.ServiceAccountName = "guard"
}
if enableTokenAuth {

if opts.tokenAuthFile != "" {
d.Spec.Template.Spec.Containers[0].Args = append(d.Spec.Template.Spec.Containers[0].Args, "--token-auth-file=/etc/guard/auth/token.csv")
volMount := core.VolumeMount{
Name: "guard-token-auth",
Expand All @@ -261,6 +268,18 @@ func newDeployment(namespace string, enableRBAC, enableTokenAuth bool) runtime.O
}
d.Spec.Template.Spec.Volumes = append(d.Spec.Template.Spec.Volumes, vol)
}

//Add server flags
if opts.Azure.ClientID != "" {
d.Spec.Template.Spec.Containers[0].Args = append(d.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--azure-client-id=%s", opts.Azure.ClientID))
}
if opts.Azure.ClientSecret != "" {
d.Spec.Template.Spec.Containers[0].Args = append(d.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--azure-client-secret=%s", opts.Azure.ClientSecret))
}
if opts.Azure.TenantID != "" {
d.Spec.Template.Spec.Containers[0].Args = append(d.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--azure-tenant-id=%s", opts.Azure.TenantID))
}

return &d
}

Expand Down
9 changes: 8 additions & 1 deletion cmds/webhok_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ func NewCmdGetWebhookConfig() *cobra.Command {
}
}
if len(args) == 0 {
log.Fatalln("Missing client name.")
if strings.ToLower(org) == "azure" {
//azure common name not required, so default common name used
args = []string{"azure"}
} else {
log.Fatalln("Missing client name.")
}
}
if len(args) > 1 {
log.Fatalln("Multiple client name found.")
Expand All @@ -50,6 +55,8 @@ func NewCmdGetWebhookConfig() *cobra.Command {
cfg.Organization = []string{"Appscode"}
case "gitlab":
cfg.Organization = []string{"Gitlab"}
case "azure":
cfg.Organization = []string{"Azure"}
case "":
log.Fatalln("Missing organization name. Set flag -o Google|Github.")
default:
Expand Down
1 change: 1 addition & 0 deletions docs/guides/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ Guides show you how to perform tasks with Guard.
- [Gitlab](/docs/guides/authenticator/gitlab.md). Explains how to use Gitlab authenticator.
- [Google](/docs/guides/authenticator/google.md). Explains how to use Google authenticator.
- [Static Token File](/docs/guides/authenticator/static_token_file.md). Explains how to authenticate using static token file.
- [Azure](/docs/guides/authenticator/azure.md). Explains how to use Azure authenticator.
- [RBAC Roles](/docs/guides/rbac.md). Documents how to configure RBAC roles for user groups.
106 changes: 106 additions & 0 deletions docs/guides/authenticator/azure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: Azure Authenticator | Guard
description: Authenticate into Kubernetes using Azure
menu:
product_guard_0.1.0-rc.5:
identifier: azure-authenticator
parent: authenticator-guides
name: Azure
weight: 10
product_name: guard
menu_name: product_guard_0.1.0-rc.5
section_menu_id: guides
---

# Azure Authenticator

TO use Azure,

1. Create a client cert with `Organization` set to `Azure`.For Azure `CommonName` is optional. To ease this process, use the Guard cli to issue a client cert/key pair.

```console
$ guard init client {common-name} -o Azure
```

2. Send additional `--azure-client-id`,`--azure-client-secret` and `--azure-tenant-id` flags to guard server. You can use following command to create YAMLs for this setup.
```console
# generate Kubernetes YAMLs for deploying guard server
$ guard get installer --azure-client-id=[APPLICATION_ID] --azure-client-secret=[APPLICATION_SECRET] --azure-tenant-id=[TENANT_ID] > installer.yaml
$ kubectl apply -f installer.yaml

```
Procedure to find `APPLICATION_ID`, `APPLICATION_SECRET` are given below. Replace the TENANT_ID with your azure tenant id.

### Configure Azure Active Directory App

1. Sign in to the [Azure portal](https://portal.azure.com/)

2. Create an Azure Active Directory Web App / API application

![create-app-registration](/docs/images/azure/create-app-registration.png)

3. Use the **Application ID** as `APPLICATION_ID`

![application-id](/docs/images/azure/application-id.png)

4. Click on the **Settings**, click on the **key** , generate a key and use this key as `APPLICATION_SECRET`

![secret-key](/docs/images/azure/secret-key.png)

5. Click on the **Manifest** , set `groupMembershipClaims` to `All` and **save** the mainfest

![update-manifest](/docs/images/azure/update-manifest.png)

6. Add **Microsoft graph** api with permission `Read directory data` and `Sign in and read user profile`.

![add-api](/docs/images/azure/add-api.png)

7. Create a second Azure Active Directory native application

![create-native-app](/docs/images/azure/create-native-app.png)

8. Use the **Application ID** of this native app as `CLIENT_ID`

![client-id](/docs/images/azure/client-id.png)

9. Add application created at step 2 with permission `Access [Application_Name_Created_At_Step_2]`

![add-guard-app](/docs/images/azure/add-guard-api.png)

## Configure kubectl

```console
kubectl config set-credentials "USER_NAME" --auth-provider=azure \
--auth-provider-arg=environment=AzurePublicCloud \
--auth-provider-arg=client-id=CLIENT_ID \
--auth-provider-arg=tenant-id=TENANT_ID \
--auth-provider-arg=apiserver-id=APPLICATION_ID
```

Procedure to find `APPLICATION_ID`, `APPLICATION_SECRET` and `CLIENT_ID` are given above. Replace the USER_NAME and TENANT_ID with your azure username and tenant id.

Or You can add user in `.kube/config` file

```yaml
...
users:
- name: USER_NAME
user:
auth-provider:
config:
apiserver-id: APPLICATION_ID
client-id: CLIENT_ID
tenant-id: TENANT_ID
environment: AzurePublicCloud
name: azure
```

The access token is acquired when first `kubectl` command is executed

```
kubectl get pods

To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code DEC7D48GA to authenticate.
```

After signing in a web browser, the token is stored in the configuration, and it will be reused when executing next commands.
Binary file added docs/images/azure/add-api.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/add-guard-api.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/application-id.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/client-id.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/create-app-registration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/create-native-app.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/secret-key.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/azure/update-manifest.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 9 additions & 6 deletions docs/reference/guard_get_installer.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ guard get installer [flags]
### Options

```
--addr string Address (host:port) of guard server. (default "10.96.10.96:9844")
-h, --help help for installer
-n, --namespace string Name of Kubernetes namespace used to run guard server. (default "kube-system")
--pki-dir string Path to directory where pki files are stored. (default "$HOME/.guard")
--rbac If true, uses RBAC with operator and database objects
--token-auth-file string Path to the token file
--addr string Address (host:port) of guard server. (default "10.96.10.96:9844")
--azure.client-id string MS Graph application client ID to use
--azure.client-secret string MS Graph application client secret to use
--azure.tenant-id string MS Graph application tenant id to use
-h, --help help for installer
-n, --namespace string Name of Kubernetes namespace used to run guard server. (default "kube-system")
--pki-dir string Path to directory where pki files are stored. (default "$HOME/.guard")
--rbac If true, uses RBAC with operator and database objects
--token-auth-file string Path to the token file
```

### Options inherited from parent commands
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/guard_get_webhook-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ guard get webhook-config [flags]
--addr string Address (host:port) of guard server. (default "10.96.10.96:9844")
-h, --help help for webhook-config
-o, --organization string Name of Organization (Github/Gitlab/Google).
--pki-dir string Path to directory where pki files are stored. (default "/home/tamal/.guard")
--pki-dir string Path to directory where pki files are stored. (default "$HOME/.guard")
```

### Options inherited from parent commands
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/guard_init_ca.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ guard init ca [flags]

```
-h, --help help for ca
--pki-dir string Path to directory where pki files are stored. (default "/home/tamal/.guard")
--pki-dir string Path to directory where pki files are stored. (default "$HOME/.guard")
```

### Options inherited from parent commands
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/guard_init_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ guard init client [flags]
```
-h, --help help for client
-o, --organization string Name of Organization (Github/Gitlab/Google).
--pki-dir string Path to directory where pki files are stored. (default "/home/tamal/.guard")
--pki-dir string Path to directory where pki files are stored. (default "$HOME/.guard")
```

### Options inherited from parent commands
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/guard_init_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ guard init server [flags]
--domains stringSlice Alternative Domain names
-h, --help help for server
--ips ipSlice Alternative IP addresses (default [127.0.0.1])
--pki-dir string Path to directory where pki files are stored. (default "/home/tamal/.guard")
--pki-dir string Path to directory where pki files are stored. (default "$HOME/.guard")
```

### Options inherited from parent commands
Expand Down