feat(ssh-import): Add ssh-import-url user attribute.
This commit is contained in:
		| @@ -132,6 +132,7 @@ All but the `passwd` and `ssh-authorized-keys` fields will be ignored if the use | ||||
| - **no-user-group**: Boolean. Skip default group creation. | ||||
| - **ssh-authorized-keys**: List of public SSH keys to authorize for this user | ||||
| - **coreos-ssh-import-github**: Authorize SSH keys from Github user | ||||
| - **coreos-ssh-import-url**: Authorize SSH keys imported from a url endpoint. | ||||
| - **system**: Create the user as a system user. No home directory will be created. | ||||
| - **no-log-init**: Boolean. Skip initialization of lastlog and faillog databases. | ||||
|  | ||||
| @@ -176,6 +177,41 @@ perl -e 'print crypt("password","\$6\$SALT\$") . "\n"' | ||||
|  | ||||
| Using a higher number of rounds will help create more secure passwords, but given enough time, password hashes can be reversed.  On most RPM based distributions there is a tool called mkpasswd available in the `expect` package, but this does not handle "rounds" nor advanced hashing algorithms.  | ||||
|  | ||||
| #### Retrieving ssh authorized keys from a GitHub user | ||||
|  | ||||
| Using the field `coreos-ssh-import-github` you can make coreos-cloudinit to add the public ssh keys from a GitHub user as authorized keys to a server. | ||||
|  | ||||
| ``` | ||||
| #cloud-config | ||||
|  | ||||
| users: | ||||
|   - name: elroy | ||||
|   coreos-ssh-import-github: elroy | ||||
| ``` | ||||
|  | ||||
| #### Retrieving ssh authorized keys from an http endpoint | ||||
|  | ||||
| Coreos-cloudinit can also pull authorized keys from any http endpoint that matches (GitHub's API response format)[http://developer.github.com/v3/users/keys/#list-public-keys-for-a-user]. | ||||
| This is useful if you have an installation of GitHub Enterprise, you can provide a complete url with an authentication token: | ||||
|  | ||||
| ``` | ||||
| #cloud-config | ||||
|  | ||||
| users: | ||||
|   - name: elroy | ||||
|   coreos-ssh-import-url: https://token:[OAUTH-TOKEN]@githubenterprise.com/users/elroy/keys | ||||
| ``` | ||||
|  | ||||
| You can also provide any url which response matches that json format for public keys: | ||||
|  | ||||
| ``` | ||||
| #cloud-config | ||||
|  | ||||
| users: | ||||
|   - name: elroy | ||||
|   coreos-ssh-import-url: https://example.com/public-keys | ||||
| ``` | ||||
|  | ||||
| ### write_files | ||||
|  | ||||
| Inject an arbitrary set of files to the local filesystem. | ||||
|   | ||||
| @@ -83,6 +83,12 @@ func Apply(cfg CloudConfig, env *Environment) error { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			if user.SSHImportURL != "" { | ||||
| 				log.Printf("Authorizing SSH keys for CoreOS user '%s' from '%s'", user.Name, user.SSHImportURL) | ||||
| 				if err := SSHImportKeysFromURL(user.Name, user.SSHImportURL); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -1,52 +1,18 @@ | ||||
| package initialize | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/coreos/coreos-cloudinit/system" | ||||
| ) | ||||
|  | ||||
| type GithubUserKey struct { | ||||
| 	Id  int    `json:"id"` | ||||
| 	Key string `json:"key"` | ||||
| } | ||||
|  | ||||
| func fetchGithubKeys(github_url string) ([]string, error) { | ||||
| 	res, err := http.Get(github_url) | ||||
| 	defer res.Body.Close() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	body, err := ioutil.ReadAll(res.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var data []GithubUserKey | ||||
| 	err = json.Unmarshal(body, &data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	keys := make([]string, 0) | ||||
| 	for _, key := range data { | ||||
| 		keys = append(keys, key.Key) | ||||
| 	} | ||||
| 	return keys, err | ||||
|  | ||||
| } | ||||
|  | ||||
| func SSHImportGithubUser(system_user string, github_user string) error { | ||||
| 	url := fmt.Sprintf("https://api.github.com/users/%s/keys", github_user) | ||||
| 	keys, err := fetchGithubKeys(url) | ||||
| 	keys, err := fetchUserKeys(url) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	key_name := fmt.Sprintf("github-%s", github_user) | ||||
| 	err = system.AuthorizeSSHKeys(system_user, key_name, keys) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| 	return system.AuthorizeSSHKeys(system_user, key_name, keys) | ||||
| } | ||||
|   | ||||
| @@ -1,48 +1,9 @@ | ||||
| package initialize | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestCloudConfigUsersGithubMarshal(t *testing.T) { | ||||
| 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		gh_res := ` | ||||
| [ | ||||
|   { | ||||
|     "id": 67057, | ||||
|     "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAIHAu822ggSkIHrJYvhmBceOSVjuflfQm8RbMMDNVe9relQfuPbN+nxGGTCKzPLebeOcX+Wwi77TPXWwK3BZMglfXxhABlFPsuMb63Tqp94pBYsJdx/iFj9iGo6pKoM1k8ubOcqsUnq+BR9895zRbE7MjdwkGo67+QhCEwvkwAnNAAAAFQCuddVqXLCubzqnWmeHLQE+2GFfHwAAAIBnlXW5h15ndVuwi0htF4oodVSB1KwnTWcuBK+aE1zRs76yvRb0Ws+oifumThDwB/Tec6FQuAfRKfy6piChZqsu5KvL98I+2t5yyi1td+kMvdTnVL2lW44etDKseOcozmknCOmh4Dqvhl/2MwrDAhlPaN08EEq9h3w3mXtNLWH64QAAAIBAzDOKr17llngaKIdDXh+LtXKh87+zfjlTA36/9r2uF2kYE5uApDtu9sPCkt7+YBQt7R8prADPckwAiXwVdk0xijIOpLDBmoydQJJRQ+zTMxvpQmUr/1kUOv0zb+lB657CgvN0vVTmP2swPeMvgntt3C4vw7Ab+O+MS9peOAJbbQ==" | ||||
|   }, | ||||
|   { | ||||
|     "id": 3340477, | ||||
|     "key": "ssh-dss AAAAB3NzaC1kc3MAAACBANxpzIbTzKTeBRaOIdUxwwGwvDasTfU/PonhbNIuhYjc+xFGvBRTumox2F+luVAKKs4WdvA4nJXaY1OFi6DZftk5Bp4E2JaSzp8ulAzHsMexDdv6LGHGEJj/qdHAL1vHk2K89PpwRFSRZI8XRBLjvkr4ZgBKLG5ZILXPJEPP2j3lAAAAFQCtxoTnV8wy0c4grcGrQ+1sCsD7WQAAAIAqZsW2GviMe1RQrbZT0xAZmI64XRPrnLsoLxycHWlS7r6uUln2c6Ae2MB/YF0d4Kd1XZii9GHj7rrypqEo7MW8uSabhu70nmu1J8m2O3Dsr+4oJLeat9vwPsJV92IKO0jQwjKnAOHOiB9JKGeCw+NfXfogbti9/q38Q6XcS+SI5wAAAIEA1803Y2h+tOOpZXAsNIwl9mRfExWzLQ3L7knwJdznQu/6SW1H/1oyoYLebuk187Qj2UFI5qQ6AZNc49DvohWx0Cg6ABcyubNyoaCjZKWIdxVnItHWNbLe//+tyTu0I2eQwJOORsEPK5gMpf599C7wXQ//DzZOWbTWiHEX52gCTmk=" | ||||
|   }, | ||||
|   { | ||||
|     "id": 5224438, | ||||
|     "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAPKRWdKhzGZuLAJL6M1eM51hWViMqNBC2C6lm2OqGRYLuIf1GJ391widUuSf4wQqnkR22Q9PCmAZ19XCf11wBRMnuw9I/Z3Bt5bXfc+dzFBCmHYGJ6wNSv++H9jxyMb+usmsenWOFZGNO2jN0wrJ4ay8Yt0bwtRU+VCXpuRLszMzAAAAFQDZUIuPjcfK5HLgnwZ/J3lvtvlUjQAAAIEApIkAwLuCQV5j3U6DmI/Y6oELqSUR2purFm8jo8jePFfe1t+ghikgD254/JXlhDCVgY0NLXcak+coJfGCTT23quJ7I5xdpTn/OZO2Q6Woum/bijFC/UWwQbLz0R2nU3DoHv5v6XHQZxuIG4Fsxa91S+vWjZFtI7RuYlBCZA//ANMAAACBAJO0FojzkX6IeaWLqrgu9GTkFwGFazZ+LPH5JOWPoPn1hQKuR32Uf6qNcBZcIjY7SF0P7HF5rLQd6zKZzHqqQQ92MV555NEwjsnJglYU8CaaZsfYooaGPgA1YN7RhTSAuDmUW5Hyfj5BH4NTtrzrvJxIhDoQLf31Fasjw00r4R0O" | ||||
|   } | ||||
| ] | ||||
| ` | ||||
| 		fmt.Fprintln(w, gh_res) | ||||
| 	})) | ||||
| 	defer ts.Close() | ||||
|  | ||||
| 	keys, err := fetchGithubKeys(ts.URL) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Encountered unexpected error: %v", err) | ||||
| 	} | ||||
| 	expected := "ssh-dss AAAAB3NzaC1kc3MAAACBAIHAu822ggSkIHrJYvhmBceOSVjuflfQm8RbMMDNVe9relQfuPbN+nxGGTCKzPLebeOcX+Wwi77TPXWwK3BZMglfXxhABlFPsuMb63Tqp94pBYsJdx/iFj9iGo6pKoM1k8ubOcqsUnq+BR9895zRbE7MjdwkGo67+QhCEwvkwAnNAAAAFQCuddVqXLCubzqnWmeHLQE+2GFfHwAAAIBnlXW5h15ndVuwi0htF4oodVSB1KwnTWcuBK+aE1zRs76yvRb0Ws+oifumThDwB/Tec6FQuAfRKfy6piChZqsu5KvL98I+2t5yyi1td+kMvdTnVL2lW44etDKseOcozmknCOmh4Dqvhl/2MwrDAhlPaN08EEq9h3w3mXtNLWH64QAAAIBAzDOKr17llngaKIdDXh+LtXKh87+zfjlTA36/9r2uF2kYE5uApDtu9sPCkt7+YBQt7R8prADPckwAiXwVdk0xijIOpLDBmoydQJJRQ+zTMxvpQmUr/1kUOv0zb+lB657CgvN0vVTmP2swPeMvgntt3C4vw7Ab+O+MS9peOAJbbQ==" | ||||
| 	if keys[0] != expected { | ||||
| 		t.Fatalf("expected %s, got %s", expected, keys[0]) | ||||
| 	} | ||||
| 	expected = "ssh-dss AAAAB3NzaC1kc3MAAACBAPKRWdKhzGZuLAJL6M1eM51hWViMqNBC2C6lm2OqGRYLuIf1GJ391widUuSf4wQqnkR22Q9PCmAZ19XCf11wBRMnuw9I/Z3Bt5bXfc+dzFBCmHYGJ6wNSv++H9jxyMb+usmsenWOFZGNO2jN0wrJ4ay8Yt0bwtRU+VCXpuRLszMzAAAAFQDZUIuPjcfK5HLgnwZ/J3lvtvlUjQAAAIEApIkAwLuCQV5j3U6DmI/Y6oELqSUR2purFm8jo8jePFfe1t+ghikgD254/JXlhDCVgY0NLXcak+coJfGCTT23quJ7I5xdpTn/OZO2Q6Woum/bijFC/UWwQbLz0R2nU3DoHv5v6XHQZxuIG4Fsxa91S+vWjZFtI7RuYlBCZA//ANMAAACBAJO0FojzkX6IeaWLqrgu9GTkFwGFazZ+LPH5JOWPoPn1hQKuR32Uf6qNcBZcIjY7SF0P7HF5rLQd6zKZzHqqQQ92MV555NEwjsnJglYU8CaaZsfYooaGPgA1YN7RhTSAuDmUW5Hyfj5BH4NTtrzrvJxIhDoQLf31Fasjw00r4R0O" | ||||
| 	if keys[2] != expected { | ||||
| 		t.Fatalf("expected %s, got %s", expected, keys[2]) | ||||
| 	} | ||||
|  | ||||
| } | ||||
| func TestCloudConfigUsersGithubUser(t *testing.T) { | ||||
|  | ||||
| 	contents := ` | ||||
|   | ||||
							
								
								
									
										47
									
								
								initialize/ssh_keys.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								initialize/ssh_keys.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| package initialize | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/coreos/coreos-cloudinit/system" | ||||
| ) | ||||
|  | ||||
| type UserKey struct { | ||||
| 	ID  int    `json:"id,omitempty"` | ||||
| 	Key string `json:"key"` | ||||
| } | ||||
|  | ||||
| func SSHImportKeysFromURL(system_user string, url string) error { | ||||
| 	keys, err := fetchUserKeys(url) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	key_name := fmt.Sprintf("coreos-cloudinit-%s", system_user) | ||||
| 	return system.AuthorizeSSHKeys(system_user, key_name, keys) | ||||
| } | ||||
|  | ||||
| func fetchUserKeys(url string) ([]string, error) { | ||||
| 	res, err := http.Get(url) | ||||
| 	defer res.Body.Close() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	body, err := ioutil.ReadAll(res.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var data []UserKey | ||||
| 	err = json.Unmarshal(body, &data) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	keys := make([]string, 0) | ||||
| 	for _, key := range data { | ||||
| 		keys = append(keys, key.Key) | ||||
| 	} | ||||
| 	return keys, err | ||||
| } | ||||
							
								
								
									
										69
									
								
								initialize/ssh_keys_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								initialize/ssh_keys_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| package initialize | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestCloudConfigUsersUrlMarshal(t *testing.T) { | ||||
| 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		gh_res := ` | ||||
| [ | ||||
|   { | ||||
|     "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAIHAu822ggSkIHrJYvhmBceOSVjuflfQm8RbMMDNVe9relQfuPbN+nxGGTCKzPLebeOcX+Wwi77TPXWwK3BZMglfXxhABlFPsuMb63Tqp94pBYsJdx/iFj9iGo6pKoM1k8ubOcqsUnq+BR9895zRbE7MjdwkGo67+QhCEwvkwAnNAAAAFQCuddVqXLCubzqnWmeHLQE+2GFfHwAAAIBnlXW5h15ndVuwi0htF4oodVSB1KwnTWcuBK+aE1zRs76yvRb0Ws+oifumThDwB/Tec6FQuAfRKfy6piChZqsu5KvL98I+2t5yyi1td+kMvdTnVL2lW44etDKseOcozmknCOmh4Dqvhl/2MwrDAhlPaN08EEq9h3w3mXtNLWH64QAAAIBAzDOKr17llngaKIdDXh+LtXKh87+zfjlTA36/9r2uF2kYE5uApDtu9sPCkt7+YBQt7R8prADPckwAiXwVdk0xijIOpLDBmoydQJJRQ+zTMxvpQmUr/1kUOv0zb+lB657CgvN0vVTmP2swPeMvgntt3C4vw7Ab+O+MS9peOAJbbQ==" | ||||
|   }, | ||||
|   { | ||||
|     "key": "ssh-dss AAAAB3NzaC1kc3MAAACBANxpzIbTzKTeBRaOIdUxwwGwvDasTfU/PonhbNIuhYjc+xFGvBRTumox2F+luVAKKs4WdvA4nJXaY1OFi6DZftk5Bp4E2JaSzp8ulAzHsMexDdv6LGHGEJj/qdHAL1vHk2K89PpwRFSRZI8XRBLjvkr4ZgBKLG5ZILXPJEPP2j3lAAAAFQCtxoTnV8wy0c4grcGrQ+1sCsD7WQAAAIAqZsW2GviMe1RQrbZT0xAZmI64XRPrnLsoLxycHWlS7r6uUln2c6Ae2MB/YF0d4Kd1XZii9GHj7rrypqEo7MW8uSabhu70nmu1J8m2O3Dsr+4oJLeat9vwPsJV92IKO0jQwjKnAOHOiB9JKGeCw+NfXfogbti9/q38Q6XcS+SI5wAAAIEA1803Y2h+tOOpZXAsNIwl9mRfExWzLQ3L7knwJdznQu/6SW1H/1oyoYLebuk187Qj2UFI5qQ6AZNc49DvohWx0Cg6ABcyubNyoaCjZKWIdxVnItHWNbLe//+tyTu0I2eQwJOORsEPK5gMpf599C7wXQ//DzZOWbTWiHEX52gCTmk=" | ||||
|   }, | ||||
|   { | ||||
|     "id": 5224438, | ||||
|     "key": "ssh-dss AAAAB3NzaC1kc3MAAACBAPKRWdKhzGZuLAJL6M1eM51hWViMqNBC2C6lm2OqGRYLuIf1GJ391widUuSf4wQqnkR22Q9PCmAZ19XCf11wBRMnuw9I/Z3Bt5bXfc+dzFBCmHYGJ6wNSv++H9jxyMb+usmsenWOFZGNO2jN0wrJ4ay8Yt0bwtRU+VCXpuRLszMzAAAAFQDZUIuPjcfK5HLgnwZ/J3lvtvlUjQAAAIEApIkAwLuCQV5j3U6DmI/Y6oELqSUR2purFm8jo8jePFfe1t+ghikgD254/JXlhDCVgY0NLXcak+coJfGCTT23quJ7I5xdpTn/OZO2Q6Woum/bijFC/UWwQbLz0R2nU3DoHv5v6XHQZxuIG4Fsxa91S+vWjZFtI7RuYlBCZA//ANMAAACBAJO0FojzkX6IeaWLqrgu9GTkFwGFazZ+LPH5JOWPoPn1hQKuR32Uf6qNcBZcIjY7SF0P7HF5rLQd6zKZzHqqQQ92MV555NEwjsnJglYU8CaaZsfYooaGPgA1YN7RhTSAuDmUW5Hyfj5BH4NTtrzrvJxIhDoQLf31Fasjw00r4R0O" | ||||
|   } | ||||
| ] | ||||
| ` | ||||
| 		fmt.Fprintln(w, gh_res) | ||||
| 	})) | ||||
| 	defer ts.Close() | ||||
|  | ||||
| 	keys, err := fetchUserKeys(ts.URL) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Encountered unexpected error: %v", err) | ||||
| 	} | ||||
| 	expected := "ssh-dss AAAAB3NzaC1kc3MAAACBAIHAu822ggSkIHrJYvhmBceOSVjuflfQm8RbMMDNVe9relQfuPbN+nxGGTCKzPLebeOcX+Wwi77TPXWwK3BZMglfXxhABlFPsuMb63Tqp94pBYsJdx/iFj9iGo6pKoM1k8ubOcqsUnq+BR9895zRbE7MjdwkGo67+QhCEwvkwAnNAAAAFQCuddVqXLCubzqnWmeHLQE+2GFfHwAAAIBnlXW5h15ndVuwi0htF4oodVSB1KwnTWcuBK+aE1zRs76yvRb0Ws+oifumThDwB/Tec6FQuAfRKfy6piChZqsu5KvL98I+2t5yyi1td+kMvdTnVL2lW44etDKseOcozmknCOmh4Dqvhl/2MwrDAhlPaN08EEq9h3w3mXtNLWH64QAAAIBAzDOKr17llngaKIdDXh+LtXKh87+zfjlTA36/9r2uF2kYE5uApDtu9sPCkt7+YBQt7R8prADPckwAiXwVdk0xijIOpLDBmoydQJJRQ+zTMxvpQmUr/1kUOv0zb+lB657CgvN0vVTmP2swPeMvgntt3C4vw7Ab+O+MS9peOAJbbQ==" | ||||
| 	if keys[0] != expected { | ||||
| 		t.Fatalf("expected %s, got %s", expected, keys[0]) | ||||
| 	} | ||||
| 	expected = "ssh-dss AAAAB3NzaC1kc3MAAACBAPKRWdKhzGZuLAJL6M1eM51hWViMqNBC2C6lm2OqGRYLuIf1GJ391widUuSf4wQqnkR22Q9PCmAZ19XCf11wBRMnuw9I/Z3Bt5bXfc+dzFBCmHYGJ6wNSv++H9jxyMb+usmsenWOFZGNO2jN0wrJ4ay8Yt0bwtRU+VCXpuRLszMzAAAAFQDZUIuPjcfK5HLgnwZ/J3lvtvlUjQAAAIEApIkAwLuCQV5j3U6DmI/Y6oELqSUR2purFm8jo8jePFfe1t+ghikgD254/JXlhDCVgY0NLXcak+coJfGCTT23quJ7I5xdpTn/OZO2Q6Woum/bijFC/UWwQbLz0R2nU3DoHv5v6XHQZxuIG4Fsxa91S+vWjZFtI7RuYlBCZA//ANMAAACBAJO0FojzkX6IeaWLqrgu9GTkFwGFazZ+LPH5JOWPoPn1hQKuR32Uf6qNcBZcIjY7SF0P7HF5rLQd6zKZzHqqQQ92MV555NEwjsnJglYU8CaaZsfYooaGPgA1YN7RhTSAuDmUW5Hyfj5BH4NTtrzrvJxIhDoQLf31Fasjw00r4R0O" | ||||
| 	if keys[2] != expected { | ||||
| 		t.Fatalf("expected %s, got %s", expected, keys[2]) | ||||
| 	} | ||||
|  | ||||
| } | ||||
| func TestCloudConfigUsersSSHImportURL(t *testing.T) { | ||||
|  | ||||
| 	contents := ` | ||||
| users: | ||||
|   - name: elroy | ||||
|     coreos-ssh-import-url: https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys | ||||
| ` | ||||
| 	cfg, err := NewCloudConfig(contents) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Encountered unexpected error: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if len(cfg.Users) != 1 { | ||||
| 		t.Fatalf("Parsed %d users, expected 1", cfg.Users) | ||||
| 	} | ||||
|  | ||||
| 	user := cfg.Users[0] | ||||
|  | ||||
| 	if user.Name != "elroy" { | ||||
| 		t.Errorf("User name is %q, expected 'elroy'", user.Name) | ||||
| 	} | ||||
|  | ||||
| 	if user.SSHImportURL != "https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys" { | ||||
| 		t.Errorf("ssh import url is %q, expected 'https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys'", user.SSHImportURL) | ||||
| 	} | ||||
| } | ||||
| @@ -13,6 +13,7 @@ type User struct { | ||||
| 	PasswordHash        string   `yaml:"passwd"` | ||||
| 	SSHAuthorizedKeys   []string `yaml:"ssh-authorized-keys"` | ||||
| 	SSHImportGithubUser string   `yaml:"coreos-ssh-import-github"` | ||||
| 	SSHImportURL        string   `yaml:"coreos-ssh-import-url"` | ||||
| 	GECOS               string   `yaml:"gecos"` | ||||
| 	Homedir             string   `yaml:"homedir"` | ||||
| 	NoCreateHome        bool     `yaml:"no-create-home"` | ||||
|   | ||||
		Reference in New Issue
	
	Block a user