github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/Documentation/examples/metadata-service/main.go (about)

     1  // Copyright 2017 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"flag"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"net/http"
    22  	"net/url"
    23  	"os"
    24  	"path"
    25  )
    26  
    27  const (
    28  	progName = "mds-example"
    29  )
    30  
    31  var (
    32  	signCommand   *flag.FlagSet
    33  	verifyCommand *flag.FlagSet
    34  
    35  	signFileFlag      *string
    36  	signSignatureFlag *string
    37  
    38  	verifyFileFlag      *string
    39  	verifyPodUUID       *string
    40  	verifySignatureFlag *string
    41  )
    42  
    43  func init() {
    44  	signCommand = flag.NewFlagSet("sign", flag.ExitOnError)
    45  	signFileFlag = signCommand.String("file", "", "File to sign")
    46  	signSignatureFlag = signCommand.String("signature", "", "Signature output file")
    47  
    48  	verifyCommand = flag.NewFlagSet("verify", flag.ExitOnError)
    49  	verifyFileFlag = verifyCommand.String("file", "", "File to verify")
    50  	verifyPodUUID = verifyCommand.String("uuid", "", "UUID of the sender pod")
    51  	verifySignatureFlag = verifyCommand.String("signature", "", "Signature file")
    52  }
    53  
    54  func usage() {
    55  	fmt.Fprintf(os.Stderr, "USAGE:\n")
    56  	fmt.Fprintf(os.Stderr, "\t%s <command> <args>\n", progName)
    57  	fmt.Fprintf(os.Stderr, "\nCOMMANDS:\n")
    58  	fmt.Fprintf(os.Stderr, "\tsign --file=FILE --signature=SIGNATURE_FILE\n")
    59  	fmt.Fprintf(os.Stderr, "\t\tsign a file with the metadata server and save signature to a file\n")
    60  	fmt.Fprintf(os.Stderr, "\tverify --file=FILE --uuid=POD_UUID --signature=SIGNATURE_FILE\n")
    61  	fmt.Fprintf(os.Stderr, "\t\tverify a file signed with the metadata server\n")
    62  }
    63  
    64  func parseArgs(args []string) error {
    65  	if len(args) < 2 {
    66  		return fmt.Errorf("missing command")
    67  	}
    68  	switch args[1] {
    69  	case "sign":
    70  		signCommand.Parse(args[2:])
    71  	case "verify":
    72  		verifyCommand.Parse(args[2:])
    73  	default:
    74  		return fmt.Errorf("%q is not a valid command.", args[1])
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  func sign(mdsURL, p, outPath string) error {
    81  	signPath := path.Join("/", "acMetadata", "v1", "pod", "hmac", "sign")
    82  	signURL := mdsURL + signPath
    83  
    84  	content, err := ioutil.ReadFile(p)
    85  	if err != nil {
    86  		return fmt.Errorf("error reading input file: %v", err)
    87  	}
    88  
    89  	v := url.Values{}
    90  	v.Set("content", string(content))
    91  
    92  	rsp, err := http.PostForm(signURL, v)
    93  	if err != nil {
    94  		return fmt.Errorf("error generating request: %v", err)
    95  	}
    96  	defer rsp.Body.Close()
    97  
    98  	data, err := ioutil.ReadAll(rsp.Body)
    99  	if err != nil {
   100  		return fmt.Errorf("error reading response: %v", err)
   101  	}
   102  
   103  	if rsp.StatusCode != http.StatusOK {
   104  		return fmt.Errorf("error signing: %v", string(data))
   105  	}
   106  
   107  	if err := ioutil.WriteFile(outPath, data, 0600); err != nil {
   108  		return fmt.Errorf("error writing signature: %v", err)
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  func verify(mdsURL, p, uuid, signaturePath string) (bool, error) {
   115  	signPath := path.Join("/", "acMetadata", "v1", "pod", "hmac", "verify")
   116  	signURL := mdsURL + signPath
   117  
   118  	content, err := ioutil.ReadFile(p)
   119  	if err != nil {
   120  		return false, fmt.Errorf("error reading input file: %v", err)
   121  	}
   122  
   123  	signatureBytes, err := ioutil.ReadFile(signaturePath)
   124  	if err != nil {
   125  		return false, fmt.Errorf("error reading signature file: %v", err)
   126  	}
   127  
   128  	v := url.Values{}
   129  	v.Set("content", string(content))
   130  	v.Set("uuid", uuid)
   131  	v.Set("signature", string(signatureBytes))
   132  
   133  	rsp, err := http.PostForm(signURL, v)
   134  	if err != nil {
   135  		return false, fmt.Errorf("error generating request: %v", err)
   136  	}
   137  	defer rsp.Body.Close()
   138  
   139  	switch rsp.StatusCode {
   140  	case http.StatusOK:
   141  		return true, nil
   142  	case http.StatusForbidden:
   143  		return false, nil
   144  	default:
   145  		return false, fmt.Errorf("unknown error: %v", http.StatusText(rsp.StatusCode))
   146  	}
   147  }
   148  
   149  func main() {
   150  	if err := parseArgs(os.Args); err != nil {
   151  		fmt.Fprintf(os.Stderr, "%s: %v\n", progName, err)
   152  		usage()
   153  		os.Exit(1)
   154  	}
   155  
   156  	mdsURL := os.Getenv("AC_METADATA_URL")
   157  	if mdsURL == "" {
   158  		fmt.Fprintf(os.Stderr, "%s: $AC_METADATA_URL env variable not found, are you in a rkt container and is the rkt metadata service running on the host?\n", progName)
   159  		os.Exit(1)
   160  	}
   161  
   162  	if signCommand.Parsed() {
   163  		if *signFileFlag == "" || *signSignatureFlag == "" {
   164  			fmt.Fprintf(os.Stderr, "%s: 'sign' needs a file to sign and an output file\n", progName)
   165  			usage()
   166  			os.Exit(1)
   167  		}
   168  
   169  		if err := sign(mdsURL, *signFileFlag, *signSignatureFlag); err != nil {
   170  			fmt.Fprintf(os.Stderr, "%s: %v\n", progName, err)
   171  			os.Exit(1)
   172  		}
   173  	} else if verifyCommand.Parsed() {
   174  		if *verifyFileFlag == "" || *verifySignatureFlag == "" || *verifyPodUUID == "" {
   175  			fmt.Fprintf(os.Stderr, "%s: 'verify' needs a file to verify, the pod UUID of the sender, and a signature file\n", progName)
   176  			usage()
   177  			os.Exit(1)
   178  		}
   179  
   180  		ok, err := verify(mdsURL, *verifyFileFlag, *verifyPodUUID, *verifySignatureFlag)
   181  		if err != nil {
   182  			fmt.Fprintf(os.Stderr, "%s: %v\n", progName, err)
   183  			os.Exit(1)
   184  		}
   185  
   186  		if ok {
   187  			fmt.Println("signature OK")
   188  		} else {
   189  			fmt.Println("signature INVALID")
   190  			os.Exit(1)
   191  		}
   192  	}
   193  
   194  	os.Exit(0)
   195  }