github.imxd.top/hashicorp/consul@v1.4.5/agent/consul/state/connect_ca_test.go (about) 1 package state 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/hashicorp/consul/agent/connect" 9 "github.com/hashicorp/consul/agent/structs" 10 "github.com/hashicorp/go-memdb" 11 "github.com/pascaldekloe/goe/verify" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestStore_CAConfig(t *testing.T) { 16 s := testStateStore(t) 17 18 expected := &structs.CAConfiguration{ 19 Provider: "consul", 20 Config: map[string]interface{}{ 21 "PrivateKey": "asdf", 22 "RootCert": "qwer", 23 "RotationPeriod": 90 * 24 * time.Hour, 24 }, 25 } 26 27 if err := s.CASetConfig(0, expected); err != nil { 28 t.Fatal(err) 29 } 30 31 idx, config, err := s.CAConfig() 32 if err != nil { 33 t.Fatal(err) 34 } 35 if idx != 0 { 36 t.Fatalf("bad: %d", idx) 37 } 38 if !reflect.DeepEqual(expected, config) { 39 t.Fatalf("bad: %#v, %#v", expected, config) 40 } 41 } 42 43 func TestStore_CAConfigCAS(t *testing.T) { 44 s := testStateStore(t) 45 46 expected := &structs.CAConfiguration{ 47 Provider: "consul", 48 } 49 50 if err := s.CASetConfig(0, expected); err != nil { 51 t.Fatal(err) 52 } 53 // Do an extra operation to move the index up by 1 for the 54 // check-and-set operation after this 55 if err := s.CASetConfig(1, expected); err != nil { 56 t.Fatal(err) 57 } 58 59 // Do a CAS with an index lower than the entry 60 ok, err := s.CACheckAndSetConfig(2, 0, &structs.CAConfiguration{ 61 Provider: "static", 62 }) 63 if ok || err != nil { 64 t.Fatalf("expected (false, nil), got: (%v, %#v)", ok, err) 65 } 66 67 // Check that the index is untouched and the entry 68 // has not been updated. 69 idx, config, err := s.CAConfig() 70 if err != nil { 71 t.Fatal(err) 72 } 73 if idx != 1 { 74 t.Fatalf("bad: %d", idx) 75 } 76 if config.Provider != "consul" { 77 t.Fatalf("bad: %#v", config) 78 } 79 80 // Do another CAS, this time with the correct index 81 ok, err = s.CACheckAndSetConfig(2, 1, &structs.CAConfiguration{ 82 Provider: "static", 83 }) 84 if !ok || err != nil { 85 t.Fatalf("expected (true, nil), got: (%v, %#v)", ok, err) 86 } 87 88 // Make sure the config was updated 89 idx, config, err = s.CAConfig() 90 if err != nil { 91 t.Fatal(err) 92 } 93 if idx != 2 { 94 t.Fatalf("bad: %d", idx) 95 } 96 if config.Provider != "static" { 97 t.Fatalf("bad: %#v", config) 98 } 99 } 100 101 func TestStore_CAConfig_Snapshot_Restore(t *testing.T) { 102 s := testStateStore(t) 103 before := &structs.CAConfiguration{ 104 Provider: "consul", 105 Config: map[string]interface{}{ 106 "PrivateKey": "asdf", 107 "RootCert": "qwer", 108 "RotationPeriod": 90 * 24 * time.Hour, 109 }, 110 } 111 if err := s.CASetConfig(99, before); err != nil { 112 t.Fatal(err) 113 } 114 115 snap := s.Snapshot() 116 defer snap.Close() 117 118 after := &structs.CAConfiguration{ 119 Provider: "static", 120 Config: map[string]interface{}{}, 121 } 122 if err := s.CASetConfig(100, after); err != nil { 123 t.Fatal(err) 124 } 125 126 snapped, err := snap.CAConfig() 127 if err != nil { 128 t.Fatalf("err: %s", err) 129 } 130 verify.Values(t, "", before, snapped) 131 132 s2 := testStateStore(t) 133 restore := s2.Restore() 134 if err := restore.CAConfig(snapped); err != nil { 135 t.Fatalf("err: %s", err) 136 } 137 restore.Commit() 138 139 idx, res, err := s2.CAConfig() 140 if err != nil { 141 t.Fatalf("err: %s", err) 142 } 143 if idx != 99 { 144 t.Fatalf("bad index: %d", idx) 145 } 146 verify.Values(t, "", before, res) 147 } 148 149 // Make sure we handle the case of a leftover blank CA config that 150 // got stuck in a snapshot, as in https://github.com/hashicorp/consul/issues/4954 151 func TestStore_CAConfig_Snapshot_Restore_BlankConfig(t *testing.T) { 152 s := testStateStore(t) 153 before := &structs.CAConfiguration{} 154 if err := s.CASetConfig(99, before); err != nil { 155 t.Fatal(err) 156 } 157 158 snap := s.Snapshot() 159 defer snap.Close() 160 161 snapped, err := snap.CAConfig() 162 if err != nil { 163 t.Fatalf("err: %s", err) 164 } 165 verify.Values(t, "", before, snapped) 166 167 s2 := testStateStore(t) 168 restore := s2.Restore() 169 if err := restore.CAConfig(snapped); err != nil { 170 t.Fatalf("err: %s", err) 171 } 172 restore.Commit() 173 174 idx, result, err := s2.CAConfig() 175 if err != nil { 176 t.Fatalf("err: %s", err) 177 } 178 if idx != 0 { 179 t.Fatalf("bad index: %d", idx) 180 } 181 if result != nil { 182 t.Fatalf("should be nil: %v", result) 183 } 184 } 185 186 func TestStore_CARootSetList(t *testing.T) { 187 assert := assert.New(t) 188 s := testStateStore(t) 189 190 // Call list to populate the watch set 191 ws := memdb.NewWatchSet() 192 _, _, err := s.CARoots(ws) 193 assert.Nil(err) 194 195 // Build a valid value 196 ca1 := connect.TestCA(t, nil) 197 198 // Set 199 ok, err := s.CARootSetCAS(1, 0, []*structs.CARoot{ca1}) 200 assert.Nil(err) 201 assert.True(ok) 202 203 // Make sure the index got updated. 204 assert.Equal(s.maxIndex(caRootTableName), uint64(1)) 205 assert.True(watchFired(ws), "watch fired") 206 207 // Read it back out and verify it. 208 expected := *ca1 209 expected.RaftIndex = structs.RaftIndex{ 210 CreateIndex: 1, 211 ModifyIndex: 1, 212 } 213 214 ws = memdb.NewWatchSet() 215 _, roots, err := s.CARoots(ws) 216 assert.Nil(err) 217 assert.Len(roots, 1) 218 actual := roots[0] 219 assert.Equal(&expected, actual) 220 } 221 222 func TestStore_CARootSet_emptyID(t *testing.T) { 223 assert := assert.New(t) 224 s := testStateStore(t) 225 226 // Call list to populate the watch set 227 ws := memdb.NewWatchSet() 228 _, _, err := s.CARoots(ws) 229 assert.Nil(err) 230 231 // Build a valid value 232 ca1 := connect.TestCA(t, nil) 233 ca1.ID = "" 234 235 // Set 236 ok, err := s.CARootSetCAS(1, 0, []*structs.CARoot{ca1}) 237 assert.NotNil(err) 238 assert.Contains(err.Error(), ErrMissingCARootID.Error()) 239 assert.False(ok) 240 241 // Make sure the index got updated. 242 assert.Equal(s.maxIndex(caRootTableName), uint64(0)) 243 assert.False(watchFired(ws), "watch fired") 244 245 // Read it back out and verify it. 246 ws = memdb.NewWatchSet() 247 _, roots, err := s.CARoots(ws) 248 assert.Nil(err) 249 assert.Len(roots, 0) 250 } 251 252 func TestStore_CARootSet_noActive(t *testing.T) { 253 assert := assert.New(t) 254 s := testStateStore(t) 255 256 // Call list to populate the watch set 257 ws := memdb.NewWatchSet() 258 _, _, err := s.CARoots(ws) 259 assert.Nil(err) 260 261 // Build a valid value 262 ca1 := connect.TestCA(t, nil) 263 ca1.Active = false 264 ca2 := connect.TestCA(t, nil) 265 ca2.Active = false 266 267 // Set 268 ok, err := s.CARootSetCAS(1, 0, []*structs.CARoot{ca1, ca2}) 269 assert.NotNil(err) 270 assert.Contains(err.Error(), "exactly one active") 271 assert.False(ok) 272 } 273 274 func TestStore_CARootSet_multipleActive(t *testing.T) { 275 assert := assert.New(t) 276 s := testStateStore(t) 277 278 // Call list to populate the watch set 279 ws := memdb.NewWatchSet() 280 _, _, err := s.CARoots(ws) 281 assert.Nil(err) 282 283 // Build a valid value 284 ca1 := connect.TestCA(t, nil) 285 ca2 := connect.TestCA(t, nil) 286 287 // Set 288 ok, err := s.CARootSetCAS(1, 0, []*structs.CARoot{ca1, ca2}) 289 assert.NotNil(err) 290 assert.Contains(err.Error(), "exactly one active") 291 assert.False(ok) 292 } 293 294 func TestStore_CARootActive_valid(t *testing.T) { 295 assert := assert.New(t) 296 s := testStateStore(t) 297 298 // Build a valid value 299 ca1 := connect.TestCA(t, nil) 300 ca1.Active = false 301 ca2 := connect.TestCA(t, nil) 302 ca3 := connect.TestCA(t, nil) 303 ca3.Active = false 304 305 // Set 306 ok, err := s.CARootSetCAS(1, 0, []*structs.CARoot{ca1, ca2, ca3}) 307 assert.Nil(err) 308 assert.True(ok) 309 310 // Query 311 ws := memdb.NewWatchSet() 312 idx, res, err := s.CARootActive(ws) 313 assert.Equal(idx, uint64(1)) 314 assert.Nil(err) 315 assert.NotNil(res) 316 assert.Equal(ca2.ID, res.ID) 317 } 318 319 // Test that querying the active CA returns the correct value. 320 func TestStore_CARootActive_none(t *testing.T) { 321 assert := assert.New(t) 322 s := testStateStore(t) 323 324 // Querying with no results returns nil. 325 ws := memdb.NewWatchSet() 326 idx, res, err := s.CARootActive(ws) 327 assert.Equal(idx, uint64(0)) 328 assert.Nil(res) 329 assert.Nil(err) 330 } 331 332 func TestStore_CARoot_Snapshot_Restore(t *testing.T) { 333 assert := assert.New(t) 334 s := testStateStore(t) 335 336 // Create some intentions. 337 roots := structs.CARoots{ 338 connect.TestCA(t, nil), 339 connect.TestCA(t, nil), 340 connect.TestCA(t, nil), 341 } 342 for _, r := range roots[1:] { 343 r.Active = false 344 } 345 346 // Force the sort order of the UUIDs before we create them so the 347 // order is deterministic. 348 id := testUUID() 349 roots[0].ID = "a" + id[1:] 350 roots[1].ID = "b" + id[1:] 351 roots[2].ID = "c" + id[1:] 352 353 // Now create 354 ok, err := s.CARootSetCAS(1, 0, roots) 355 assert.Nil(err) 356 assert.True(ok) 357 358 // Snapshot the queries. 359 snap := s.Snapshot() 360 defer snap.Close() 361 362 // Alter the real state store. 363 ok, err = s.CARootSetCAS(2, 1, roots[:1]) 364 assert.Nil(err) 365 assert.True(ok) 366 367 // Verify the snapshot. 368 assert.Equal(snap.LastIndex(), uint64(1)) 369 dump, err := snap.CARoots() 370 assert.Nil(err) 371 assert.Equal(roots, dump) 372 373 // Restore the values into a new state store. 374 func() { 375 s := testStateStore(t) 376 restore := s.Restore() 377 for _, r := range dump { 378 assert.Nil(restore.CARoot(r)) 379 } 380 restore.Commit() 381 382 // Read the restored values back out and verify that they match. 383 idx, actual, err := s.CARoots(nil) 384 assert.Nil(err) 385 assert.Equal(idx, uint64(2)) 386 assert.Equal(roots, actual) 387 }() 388 } 389 390 func TestStore_CABuiltinProvider(t *testing.T) { 391 assert := assert.New(t) 392 s := testStateStore(t) 393 394 { 395 expected := &structs.CAConsulProviderState{ 396 ID: "foo", 397 PrivateKey: "a", 398 RootCert: "b", 399 } 400 401 ok, err := s.CASetProviderState(0, expected) 402 assert.NoError(err) 403 assert.True(ok) 404 405 idx, state, err := s.CAProviderState(expected.ID) 406 assert.NoError(err) 407 assert.Equal(idx, uint64(0)) 408 assert.Equal(expected, state) 409 } 410 411 { 412 expected := &structs.CAConsulProviderState{ 413 ID: "bar", 414 PrivateKey: "c", 415 RootCert: "d", 416 } 417 418 ok, err := s.CASetProviderState(1, expected) 419 assert.NoError(err) 420 assert.True(ok) 421 422 idx, state, err := s.CAProviderState(expected.ID) 423 assert.NoError(err) 424 assert.Equal(idx, uint64(1)) 425 assert.Equal(expected, state) 426 } 427 } 428 429 func TestStore_CABuiltinProvider_Snapshot_Restore(t *testing.T) { 430 assert := assert.New(t) 431 s := testStateStore(t) 432 433 // Create multiple state entries. 434 before := []*structs.CAConsulProviderState{ 435 { 436 ID: "bar", 437 PrivateKey: "y", 438 RootCert: "z", 439 }, 440 { 441 ID: "foo", 442 PrivateKey: "a", 443 RootCert: "b", 444 }, 445 } 446 447 for i, state := range before { 448 ok, err := s.CASetProviderState(uint64(98+i), state) 449 assert.NoError(err) 450 assert.True(ok) 451 } 452 453 // Take a snapshot. 454 snap := s.Snapshot() 455 defer snap.Close() 456 457 // Modify the state store. 458 after := &structs.CAConsulProviderState{ 459 ID: "foo", 460 PrivateKey: "c", 461 RootCert: "d", 462 } 463 ok, err := s.CASetProviderState(100, after) 464 assert.NoError(err) 465 assert.True(ok) 466 467 snapped, err := snap.CAProviderState() 468 assert.NoError(err) 469 assert.Equal(before, snapped) 470 471 // Restore onto a new state store. 472 s2 := testStateStore(t) 473 restore := s2.Restore() 474 for _, entry := range snapped { 475 assert.NoError(restore.CAProviderState(entry)) 476 } 477 restore.Commit() 478 479 // Verify the restored values match those from before the snapshot. 480 for _, state := range before { 481 idx, res, err := s2.CAProviderState(state.ID) 482 assert.NoError(err) 483 assert.Equal(idx, uint64(99)) 484 assert.Equal(state, res) 485 } 486 }