terraform: Do not persist sensitive state

This commit is contained in:
Armon Dadgar 2014-07-10 12:01:26 -07:00
parent a79e222ae3
commit 3e608ee8b9
2 changed files with 53 additions and 1 deletions

View File

@ -131,6 +131,21 @@ func (s *State) String() string {
return buf.String() return buf.String()
} }
// sensitiveState is used to store sensitive state information
// that should not be serialized. This is only used temporarily
// and is restored into the state.
type sensitiveState struct {
ConnInfo map[string]*ResourceConnectionInfo
once sync.Once
}
func (s *sensitiveState) init() {
s.once.Do(func() {
s.ConnInfo = make(map[string]*ResourceConnectionInfo)
})
}
// The format byte is prefixed into the state file format so that we have // The format byte is prefixed into the state file format so that we have
// the ability in the future to change the file format if we want for any // the ability in the future to change the file format if we want for any
// reason. // reason.
@ -172,7 +187,25 @@ func WriteState(d *State, dst io.Writer) error {
return errors.New("failed to write state version byte") return errors.New("failed to write state version byte")
} }
return gob.NewEncoder(dst).Encode(d) // Prevent sensitive information from being serialized
sensitive := &sensitiveState{}
sensitive.init()
for name, r := range d.Resources {
if r.ConnInfo != nil {
sensitive.ConnInfo[name] = r.ConnInfo
r.ConnInfo = nil
}
}
// Serialize the state
err = gob.NewEncoder(dst).Encode(d)
// Restore the state
for name, info := range sensitive.ConnInfo {
d.Resources[name].ConnInfo = info
}
return err
} }
// ResourceConnectionInfo holds addresses, credentials and configuration // ResourceConnectionInfo holds addresses, credentials and configuration

View File

@ -98,20 +98,39 @@ func TestReadWriteState(t *testing.T) {
Resources: map[string]*ResourceState{ Resources: map[string]*ResourceState{
"foo": &ResourceState{ "foo": &ResourceState{
ID: "bar", ID: "bar",
ConnInfo: &ResourceConnectionInfo{
Type: "ssh",
Raw: map[string]string{
"user": "root",
"password": "supersecret",
},
},
}, },
}, },
} }
// Checksum before the write
chksum := checksumStruct(t, state)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := WriteState(state, buf); err != nil { if err := WriteState(state, buf); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
// Checksum after the write
chksumAfter := checksumStruct(t, state)
if chksumAfter != chksum {
t.Fatalf("structure changed during serialization!")
}
actual, err := ReadState(buf) actual, err := ReadState(buf)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
// ReadState should not restore sensitive information!
state.Resources["foo"].ConnInfo = nil
if !reflect.DeepEqual(actual, state) { if !reflect.DeepEqual(actual, state) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }