10
"github.com/juju/errors"
13
// tempCertFile is a temporary file containing an x509 certificate.
14
// It's possible to pass a certificate to libcurl in-memory, but much more
15
// complicated. We went with this hack for now. Call newTempCertFile to
16
// store a certificate in a temporary file, and once you're done with the
17
// file, invoke its Delete method to clean it up.
18
type tempCertFile struct {
23
// Path returns the full absolute path for the temporary certificate file.
24
func (certFile *tempCertFile) Path() string {
25
return path.Join(certFile.tempDir, certFile.filename)
28
// Delete cleans up a tempCertFile. You must call this after use, or you'll
29
// leave not just garbage but security-sensitive garbage.
30
// This method is idempotent. If called after it's already been run, it
32
func (certFile *tempCertFile) Delete() {
33
if certFile.tempDir == "" {
34
// Either it wasn't constructed, or it's been deleted already.
37
err := os.RemoveAll(certFile.tempDir)
41
// We no longer own a file that needs cleaning up.
42
certFile.filename = ""
46
// newTempCertFile stores the given x509 certificate in a temporary file,
47
// which only the current user will be allowed to access.
48
// You *must* clean up the file after use, by calling its Delete method.
49
func newTempCertFile(data []byte) (certFile *tempCertFile, err error) {
50
// Add context to any error we may return.
51
defer errors.Maskf(&err, "failed while writing temporary certificate file")
53
// Access permissions for these temporary files:
55
// Owner can read/write temporary files. Not backed up.
56
fileMode = 0600 | os.ModeTemporary | os.ModeExclusive
57
// Temporary dirs are like files, but owner also has "x"
59
dirMode = fileMode | 0100
62
certFile = &tempCertFile{}
64
// We'll randomize the file's name, so that even someone with access
65
// to the temporary directory (perhaps a group member sneaking in
66
// just before we close access to the directory) won't be able to
67
// guess its name and inject their own file.
68
certFile.filename = fmt.Sprintf("x509-%d.cert", rand.Int31())
70
// To guarantee that nobody else will be able to access the file, even
71
// by predicting or guessing its name, we create the file in its own
73
certFile.tempDir, err = ioutil.TempDir("", "juju-azure")
77
err = os.Chmod(certFile.tempDir, dirMode)
82
// Now, at last, write the file. WriteFile could have done most of
83
// the work on its own, but it doesn't guarantee that nobody creates
84
// a file of the same name first. When that happens, you get a file
85
// but not with the requested permissions.
86
err = ioutil.WriteFile(certFile.Path(), data, fileMode)
88
os.RemoveAll(certFile.tempDir)