2017-10-25 19:43:20 +00:00
package google
import (
"fmt"
2018-08-17 23:00:13 +00:00
"log"
2017-10-25 19:43:20 +00:00
"github.com/hashicorp/terraform/helper/encryption"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"google.golang.org/api/iam/v1"
)
func resourceGoogleServiceAccountKey ( ) * schema . Resource {
return & schema . Resource {
Create : resourceGoogleServiceAccountKeyCreate ,
Read : resourceGoogleServiceAccountKeyRead ,
Delete : resourceGoogleServiceAccountKeyDelete ,
Schema : map [ string ] * schema . Schema {
// Required
"service_account_id" : & schema . Schema {
2018-03-26 22:44:34 +00:00
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
2017-10-25 19:43:20 +00:00
} ,
// Optional
"key_algorithm" : & schema . Schema {
Type : schema . TypeString ,
Default : "KEY_ALG_RSA_2048" ,
Optional : true ,
ForceNew : true ,
ValidateFunc : validation . StringInSlice ( [ ] string { "KEY_ALG_UNSPECIFIED" , "KEY_ALG_RSA_1024" , "KEY_ALG_RSA_2048" } , false ) ,
} ,
"pgp_key" : {
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
"private_key_type" : & schema . Schema {
Type : schema . TypeString ,
Default : "TYPE_GOOGLE_CREDENTIALS_FILE" ,
Optional : true ,
ForceNew : true ,
ValidateFunc : validation . StringInSlice ( [ ] string { "TYPE_UNSPECIFIED" , "TYPE_PKCS12_FILE" , "TYPE_GOOGLE_CREDENTIALS_FILE" } , false ) ,
} ,
"public_key_type" : & schema . Schema {
Type : schema . TypeString ,
2017-11-06 18:56:10 +00:00
Default : "TYPE_X509_PEM_FILE" ,
2017-10-25 19:43:20 +00:00
Optional : true ,
ForceNew : true ,
ValidateFunc : validation . StringInSlice ( [ ] string { "TYPE_NONE" , "TYPE_X509_PEM_FILE" , "TYPE_RAW_PUBLIC_KEY" } , false ) ,
} ,
// Computed
"name" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
ForceNew : true ,
} ,
"public_key" : {
Type : schema . TypeString ,
Computed : true ,
ForceNew : true ,
} ,
"private_key" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
Sensitive : true ,
} ,
"valid_after" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"valid_before" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"private_key_encrypted" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"private_key_fingerprint" : {
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
}
}
func resourceGoogleServiceAccountKeyCreate ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
2018-06-18 20:37:41 +00:00
serviceAccountName , err := serviceAccountFQN ( d . Get ( "service_account_id" ) . ( string ) , d , config )
2018-06-01 00:31:45 +00:00
if err != nil {
return err
2018-03-26 22:44:34 +00:00
}
2017-10-25 19:43:20 +00:00
r := & iam . CreateServiceAccountKeyRequest {
KeyAlgorithm : d . Get ( "key_algorithm" ) . ( string ) ,
PrivateKeyType : d . Get ( "private_key_type" ) . ( string ) ,
}
2018-06-01 00:31:45 +00:00
sak , err := config . clientIAM . Projects . ServiceAccounts . Keys . Create ( serviceAccountName , r ) . Do ( )
2017-10-25 19:43:20 +00:00
if err != nil {
return fmt . Errorf ( "Error creating service account key: %s" , err )
}
d . SetId ( sak . Name )
// Data only available on create.
d . Set ( "valid_after" , sak . ValidAfterTime )
d . Set ( "valid_before" , sak . ValidBeforeTime )
if v , ok := d . GetOk ( "pgp_key" ) ; ok {
encryptionKey , err := encryption . RetrieveGPGKey ( v . ( string ) )
if err != nil {
return err
}
fingerprint , encrypted , err := encryption . EncryptValue ( encryptionKey , sak . PrivateKeyData , "Google Service Account Key" )
if err != nil {
return err
}
d . Set ( "private_key_encrypted" , encrypted )
d . Set ( "private_key_fingerprint" , fingerprint )
} else {
d . Set ( "private_key" , sak . PrivateKeyData )
}
err = serviceAccountKeyWaitTime ( config . clientIAM . Projects . ServiceAccounts . Keys , d . Id ( ) , d . Get ( "public_key_type" ) . ( string ) , "Creating Service account key" , 4 )
if err != nil {
return err
}
return resourceGoogleServiceAccountKeyRead ( d , meta )
}
func resourceGoogleServiceAccountKeyRead ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
publicKeyType := d . Get ( "public_key_type" ) . ( string )
// Confirm the service account key exists
sak , err := config . clientIAM . Projects . ServiceAccounts . Keys . Get ( d . Id ( ) ) . PublicKeyType ( publicKeyType ) . Do ( )
if err != nil {
2018-08-17 23:00:13 +00:00
if err = handleNotFoundError ( err , d , fmt . Sprintf ( "Service Account Key %q" , d . Id ( ) ) ) ; err == nil {
return nil
} else {
// This resource also returns 403 when it's not found.
if isGoogleApiErrorWithCode ( err , 403 ) {
log . Printf ( "[DEBUG] Got a 403 error trying to read service account key %s, assuming it's gone." , d . Id ( ) )
d . SetId ( "" )
return nil
} else {
return err
}
}
2017-10-25 19:43:20 +00:00
}
d . Set ( "name" , sak . Name )
d . Set ( "key_algorithm" , sak . KeyAlgorithm )
d . Set ( "public_key" , sak . PublicKeyData )
return nil
}
func resourceGoogleServiceAccountKeyDelete ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
_ , err := config . clientIAM . Projects . ServiceAccounts . Keys . Delete ( d . Id ( ) ) . Do ( )
2018-08-17 23:00:13 +00:00
2017-10-25 19:43:20 +00:00
if err != nil {
2018-08-17 23:00:13 +00:00
if err = handleNotFoundError ( err , d , fmt . Sprintf ( "Service Account Key %q" , d . Id ( ) ) ) ; err == nil {
return nil
} else {
// This resource also returns 403 when it's not found.
if isGoogleApiErrorWithCode ( err , 403 ) {
log . Printf ( "[DEBUG] Got a 403 error trying to read service account key %s, assuming it's gone." , d . Id ( ) )
d . SetId ( "" )
return nil
} else {
return err
}
}
2017-10-25 19:43:20 +00:00
}
d . SetId ( "" )
return nil
}