github.com/openshift/installer@v1.4.17/pkg/asset/password/password.go (about)

     1  package password
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"math/big"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"golang.org/x/crypto/bcrypt"
    11  
    12  	"github.com/openshift/installer/pkg/asset"
    13  )
    14  
    15  var (
    16  	// kubeadminPasswordPath is the path where kubeadmin user password is stored.
    17  	kubeadminPasswordPath = filepath.Join("auth", "kubeadmin-password")
    18  )
    19  
    20  // KubeadminPassword is the asset for the kubeadmin user password
    21  type KubeadminPassword struct {
    22  	Password     string
    23  	PasswordHash []byte
    24  	File         *asset.File
    25  }
    26  
    27  var _ asset.WritableAsset = (*KubeadminPassword)(nil)
    28  
    29  // Dependencies returns no dependencies.
    30  func (a *KubeadminPassword) Dependencies() []asset.Asset {
    31  	return []asset.Asset{}
    32  }
    33  
    34  // Generate the kubeadmin password
    35  func (a *KubeadminPassword) Generate(context.Context, asset.Parents) error {
    36  	err := a.generateRandomPasswordHash(23)
    37  	if err != nil {
    38  		return err
    39  	}
    40  	return nil
    41  }
    42  
    43  // generateRandomPasswordHash generates a hash of a random ASCII password
    44  // 5char-5char-5char-5char
    45  func (a *KubeadminPassword) generateRandomPasswordHash(length int) error {
    46  	const (
    47  		lowerLetters = "abcdefghijkmnopqrstuvwxyz"
    48  		upperLetters = "ABCDEFGHIJKLMNPQRSTUVWXYZ"
    49  		digits       = "23456789"
    50  		all          = lowerLetters + upperLetters + digits
    51  	)
    52  	var password string
    53  	for i := 0; i < length; i++ {
    54  		n, err := rand.Int(rand.Reader, big.NewInt(int64(len(all))))
    55  		if err != nil {
    56  			return err
    57  		}
    58  		newchar := string(all[n.Int64()])
    59  		if password == "" {
    60  			password = newchar
    61  		}
    62  		if i < length-1 {
    63  			n, err = rand.Int(rand.Reader, big.NewInt(int64(len(password)+1)))
    64  			if err != nil {
    65  				return err
    66  			}
    67  			j := n.Int64()
    68  			password = password[0:j] + newchar + password[j:]
    69  		}
    70  	}
    71  	pw := []rune(password)
    72  	for _, replace := range []int{5, 11, 17} {
    73  		pw[replace] = '-'
    74  	}
    75  	if a.Password == "" {
    76  		a.Password = string(pw)
    77  	}
    78  	bytes, err := bcrypt.GenerateFromPassword([]byte(a.Password), bcrypt.DefaultCost)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	a.PasswordHash = bytes
    83  
    84  	a.File = &asset.File{
    85  		Filename: kubeadminPasswordPath,
    86  		Data:     []byte(a.Password),
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  // Name returns the human-friendly name of the asset.
    93  func (a *KubeadminPassword) Name() string {
    94  	return "Kubeadmin Password"
    95  }
    96  
    97  // Files returns the password file.
    98  func (a *KubeadminPassword) Files() []*asset.File {
    99  	if a.File != nil {
   100  		return []*asset.File{a.File}
   101  	}
   102  	return []*asset.File{}
   103  }
   104  
   105  // Load loads a predefined hash only, if one is supplied
   106  func (a *KubeadminPassword) Load(f asset.FileFetcher) (found bool, err error) {
   107  	hashFilePath := filepath.Join("tls", "kubeadmin-password.hash")
   108  	hashFile, err := f.FetchByName(hashFilePath)
   109  	if err != nil {
   110  		if os.IsNotExist(err) {
   111  			return false, nil
   112  		}
   113  		return false, err
   114  	}
   115  
   116  	a.PasswordHash = hashFile.Data
   117  	// Assisted-service expects to always see a password file, so generate an
   118  	// empty one
   119  	a.File = &asset.File{
   120  		Filename: kubeadminPasswordPath,
   121  	}
   122  	return true, nil
   123  }