github.com/Cloud-Foundations/Dominator@v0.3.4/lib/srpc/metadata.go (about)

     1  package srpc
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/Cloud-Foundations/Dominator/lib/constants"
    15  	"github.com/Cloud-Foundations/Dominator/lib/format"
    16  	"github.com/Cloud-Foundations/Dominator/lib/stringutil"
    17  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    18  )
    19  
    20  var (
    21  	smallStackOwnersLock     sync.Mutex
    22  	_smallStackOwners        *smallStackOwnersType
    23  	startedReadingSmallStack sync.Once
    24  )
    25  
    26  type smallStackOwnersType struct {
    27  	groups []string
    28  	users  map[string]struct{}
    29  }
    30  
    31  func checkSmallStack() bool {
    32  	resp, err := http.Get(constants.MetadataUrl +
    33  		constants.SmallStackDataSource)
    34  	if err != nil {
    35  		return false
    36  	}
    37  	if resp.StatusCode != http.StatusOK {
    38  		return false
    39  	}
    40  	defer resp.Body.Close()
    41  	buffer := make([]byte, 10)
    42  	if length, _ := resp.Body.Read(buffer); length >= 4 {
    43  		if string(buffer[:4]) == "true" {
    44  			return true
    45  		}
    46  	}
    47  	return false
    48  }
    49  
    50  func getSmallStackOwners() *smallStackOwnersType {
    51  	smallStackOwnersLock.Lock()
    52  	defer smallStackOwnersLock.Unlock()
    53  	return _smallStackOwners
    54  }
    55  
    56  func loadCertificatesFromMetadata(timeout time.Duration, errorIfMissing bool,
    57  	errorIfExpired bool) (
    58  	*tls.Certificate, error) {
    59  	certPEM, err := readMetadataFile(constants.MetadataIdentityCert, timeout)
    60  	if err != nil {
    61  		if errorIfMissing {
    62  			return nil, err
    63  		}
    64  		return nil, nil
    65  	}
    66  	keyPEM, err := readMetadataFile(constants.MetadataIdentityKey, timeout)
    67  	if err != nil {
    68  		if errorIfMissing {
    69  			return nil, err
    70  		}
    71  		return nil, nil
    72  	}
    73  	tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	if errorIfExpired {
    82  		now := time.Now()
    83  		if notYet := x509Cert.NotBefore.Sub(now); notYet > 0 {
    84  			return nil, fmt.Errorf("cert will not be valid for %s",
    85  				format.Duration(notYet))
    86  		}
    87  		if expired := now.Sub(x509Cert.NotAfter); expired > 0 {
    88  			return nil, fmt.Errorf("cert expired %s ago",
    89  				format.Duration(expired))
    90  		}
    91  	}
    92  	tlsCert.Leaf = x509Cert
    93  	return &tlsCert, nil
    94  }
    95  
    96  func readMetadataFile(filename string, timeout time.Duration) ([]byte, error) {
    97  	client := http.Client{Timeout: timeout}
    98  	resp, err := client.Get(constants.MetadataUrl + filename)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	if resp.StatusCode != http.StatusOK {
   103  		return nil, errors.New(resp.Status)
   104  	}
   105  	defer resp.Body.Close()
   106  	data, err := io.ReadAll(resp.Body)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	return data, nil
   111  }
   112  
   113  func readSmallStackMetaData() {
   114  	var vmInfo proto.VmInfo
   115  	resp, err := http.Get(constants.MetadataUrl + constants.MetadataIdentityDoc)
   116  	if err != nil {
   117  		return
   118  	}
   119  	if resp.StatusCode != http.StatusOK {
   120  		return
   121  	}
   122  	defer resp.Body.Close()
   123  	decoder := json.NewDecoder(resp.Body)
   124  	if err := decoder.Decode(&vmInfo); err != nil {
   125  		return
   126  	}
   127  	smallStackOwners := &smallStackOwnersType{
   128  		groups: vmInfo.OwnerGroups,
   129  		users:  stringutil.ConvertListToMap(vmInfo.OwnerUsers, false),
   130  	}
   131  	logger.Debugf(1, "VM OwnerUsers: %v, OwnerGroups: %v\n",
   132  		vmInfo.OwnerUsers, vmInfo.OwnerGroups)
   133  	smallStackOwnersLock.Lock()
   134  	defer smallStackOwnersLock.Unlock()
   135  	_smallStackOwners = smallStackOwners
   136  }
   137  
   138  func readSmallStackMetaDataLoop() {
   139  	if !checkSmallStack() {
   140  		return
   141  	}
   142  	logger.Debugln(0,
   143  		"Running on SmallStack: will grant method access to VM owners")
   144  	for ; true; time.Sleep(10 * time.Second) {
   145  		readSmallStackMetaData()
   146  	}
   147  }
   148  
   149  func startReadingSmallStackMetaData() {
   150  	if !*srpcTrustVmOwners {
   151  		return
   152  	}
   153  	startedReadingSmallStack.Do(func() { go readSmallStackMetaDataLoop() })
   154  }