in lib/ec2macosinit/sshkeys.go [22:145]
func (c *SSHKeysModule) Do(ctx *ModuleContext) (message string, err error) {
// If we're not getting the key from IMDS and there are no keys provided, there's nothing to do here
if !c.GetIMDSOpenSSHKey && len(c.StaticOpenSSHKeys) == 0 {
return "nothing to do", nil
}
// If user is undefined, default to ec2-user
if c.User == "" {
c.User = "ec2-user"
}
// Verify that user exists
exists, err := userExists(c.User)
if err != nil {
return "", fmt.Errorf("ec2macosinit: error while checking if user %s exists: %s\n", c.User, err)
}
if !exists { // if the user doesn't exist, error out
return "", fmt.Errorf("ec2macosinit: user %s does not exist\n", c.User)
}
// Set directory and authorized_keys file
authorizedKeysDir := filepath.Join("/Users", c.User, ".ssh")
authorizedKeysFile := filepath.Join(authorizedKeysDir, "authorized_keys")
if _, err := os.Stat(authorizedKeysDir); os.IsNotExist(err) { // If directory doesn't exist, create it
err := os.MkdirAll(authorizedKeysDir, 0700)
if err != nil {
return "", fmt.Errorf("ec2macosinit: unable to create directory [%s]: %s\n", authorizedKeysDir, err)
}
}
// Get IMDS key
keySet := map[string]struct{}{}
if c.GetIMDSOpenSSHKey {
// Get IMDS property "meta-data/public-keys/0/openssh-key"
imdsKey, respCode, err := ctx.IMDS.getIMDSProperty("meta-data/public-keys/0/openssh-key")
if err != nil {
return "", fmt.Errorf("ec2macosinit: error getting openSSH key from IMDS: %s\n", err)
}
if respCode == 200 { // 200 = ok
keySet[strings.TrimSpace(imdsKey)] = struct{}{}
} else if respCode != 404 { // 404 is the only other allowable response code as it indicates no key was provided - if not 404 error out
return "", fmt.Errorf("ec2macosinit: received an unexpected response code from IMDS: %d - %s\n", respCode, err)
}
}
// Add all unique provided static keys
if len(c.StaticOpenSSHKeys) > 0 {
for _, k := range c.StaticOpenSSHKeys {
keySet[strings.TrimSpace(k)] = struct{}{}
}
}
// If authorized_keys file exists and deduplication is requested, read file and add to set
if _, err := os.Stat(authorizedKeysFile); err == nil && c.DedupKeys {
file, err := os.Open(authorizedKeysFile)
if err != nil {
return "", fmt.Errorf("ec2macosinit: unable to open %s: %s\n", authorizedKeysFile, err)
}
defer file.Close()
// Read file and add each line to set
scanner := bufio.NewScanner(file)
for scanner.Scan() {
keySet[strings.TrimSpace(scanner.Text())] = struct{}{}
}
if err := scanner.Err(); err != nil {
return "", fmt.Errorf("ec2macosinit: error while reading %s: %s\n", authorizedKeysFile, err)
}
// Set OverwriteAuthorizedKeys to true so that duplicate keys are overwritten
c.OverwriteAuthorizedKeys = true
}
// Check if there's anything else to do
if len(keySet) == 0 && !c.OverwriteAuthorizedKeys {
return "no keys found and not overwriting authorized_keys", nil
}
// Add all keys to a slice
var keys []string
for k := range keySet {
keys = append(keys, k)
}
// Write to authorized_keys file
var f *os.File
if !c.OverwriteAuthorizedKeys {
// Append to authorized_keys
f, err = os.OpenFile(authorizedKeysFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
} else {
// Overwrite (truncate) authorized_keys
f, err = os.OpenFile(authorizedKeysFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600)
}
if err != nil {
f.Close()
return "", fmt.Errorf("ec2macosinit: error while opening authorized_keys file: %s\n", err)
}
if _, err := f.WriteString(strings.Join(keys, "\n") + "\n"); err != nil {
return "", fmt.Errorf("ec2macosinit: error while writing to authorized_keys file: %s\n", err)
}
f.Close()
// Get UID and GID for user
uid, gid, err := getUIDandGID(c.User)
if err != nil && c.User == "ec2-user" {
// Use default values for ec2-user
uid = 501
gid = 20
} else if err != nil {
return "", fmt.Errorf("ec2macosinit: error while getting user info: %s\n", err)
}
// Fix file ownership and directory permissions
err = os.Chown(authorizedKeysDir, uid, gid)
if err != nil {
return "", fmt.Errorf("ec2macosinit: unable to change ownership of .ssh directory: %s\n", err)
}
err = os.Chown(authorizedKeysFile, uid, gid)
if err != nil {
return "", fmt.Errorf("ec2macosinit: unable to change ownership of authorized_keys file: %s\n", err)
}
return fmt.Sprintf("successfully added %d keys to authorized_users", len(keys)), nil
}